locomotivecms_steam 1.2.0.beta1 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/Gemfile.lock +36 -36
  4. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb +9 -1
  5. data/lib/locomotive/steam/decorators/page_decorator.rb +20 -0
  6. data/lib/locomotive/steam/decorators/template_decorator.rb +0 -1
  7. data/lib/locomotive/steam/entities/content_entry.rb +5 -4
  8. data/lib/locomotive/steam/entities/content_type.rb +5 -0
  9. data/lib/locomotive/steam/entities/page.rb +1 -2
  10. data/lib/locomotive/steam/liquid/drops/base.rb +17 -13
  11. data/lib/locomotive/steam/liquid/drops/content_entry.rb +5 -1
  12. data/lib/locomotive/steam/liquid/drops/metafields.rb +8 -3
  13. data/lib/locomotive/steam/liquid/filters/misc.rb +1 -1
  14. data/lib/locomotive/steam/liquid/filters/resize.rb +1 -1
  15. data/lib/locomotive/steam/liquid/tags/with_scope.rb +12 -1
  16. data/lib/locomotive/steam/middlewares/entry_submission.rb +23 -4
  17. data/lib/locomotive/steam/middlewares/page.rb +12 -2
  18. data/lib/locomotive/steam/middlewares/renderer.rb +7 -6
  19. data/lib/locomotive/steam/middlewares/sitemap.rb +11 -0
  20. data/lib/locomotive/steam/middlewares/thread_safe.rb +4 -0
  21. data/lib/locomotive/steam/models/i18n_field.rb +1 -1
  22. data/lib/locomotive/steam/repositories/content_type_field_repository.rb +3 -1
  23. data/lib/locomotive/steam/server.rb +0 -1
  24. data/lib/locomotive/steam/services/external_api_service.rb +8 -1
  25. data/lib/locomotive/steam/services/image_resizer_service.rb +1 -1
  26. data/lib/locomotive/steam/services/page_finder_service.rb +4 -0
  27. data/lib/locomotive/steam/version.rb +1 -1
  28. data/locomotivecms_steam.gemspec +4 -5
  29. data/spec/fixtures/default/app/views/pages/all.liquid.haml +4 -1
  30. data/spec/fixtures/default/app/views/pages/contact.liquid.haml +8 -1
  31. data/spec/fixtures/default/app/views/pages/events.liquid.haml +7 -0
  32. data/spec/fixtures/default/app/views/pages/tags/nav_in_deep.liquid.haml +2 -2
  33. data/spec/fixtures/default/data/updates.yml +4 -2
  34. data/spec/integration/server/contact_form_spec.rb +13 -0
  35. data/spec/integration/server/nav_spec.rb +4 -0
  36. data/spec/integration/server/sitemap_spec.rb +2 -2
  37. data/spec/support/helpers.rb +2 -0
  38. data/spec/unit/adapters/filesystem/yaml_loaders/content_entry_spec.rb +17 -0
  39. data/spec/unit/decorators/page_decorator_spec.rb +36 -0
  40. data/spec/unit/decorators/template_decorator_spec.rb +1 -0
  41. data/spec/unit/entities/content_type_spec.rb +34 -0
  42. data/spec/unit/entities/page_spec.rb +0 -24
  43. data/spec/unit/liquid/drops/content_entry_spec.rb +10 -2
  44. data/spec/unit/liquid/drops/metafields_spec.rb +35 -6
  45. data/spec/unit/liquid/filters/resize_spec.rb +17 -0
  46. data/spec/unit/liquid/tags/with_scope_spec.rb +15 -0
  47. data/spec/unit/middlewares/page_spec.rb +63 -0
  48. data/spec/unit/middlewares/renderer_spec.rb +2 -4
  49. data/spec/unit/middlewares/sitemap_spec.rb +41 -1
  50. data/spec/unit/services/external_api_service_spec.rb +10 -0
  51. data/spec/unit/services/image_resizer_service_spec.rb +3 -3
  52. metadata +15 -24
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Locomotive::Steam::Decorators::PageDecorator do
4
+
5
+ let(:redirect) { nil }
6
+ let(:redirect_url) { nil }
7
+ let(:page) { instance_double('Page', localized_attributes: [], redirect: redirect, redirect_url: redirect_url) }
8
+ let(:locale) { 'fr' }
9
+ let(:default_locale) { 'en' }
10
+ let(:decorated) { described_class.new(page, locale, default_locale) }
11
+
12
+ describe '#redirect?' do
13
+
14
+ subject { decorated.redirect? }
15
+
16
+ it { is_expected.to eq false }
17
+
18
+ context 'redirect_url has been set' do
19
+
20
+ let(:redirect_url) { 'http://www.google.fr' }
21
+
22
+ it { is_expected.to eq true }
23
+
24
+ context 'but redirect is set to false' do
25
+
26
+ let(:redirect) { false }
27
+
28
+ it { is_expected.to eq false }
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'haml'
2
3
 
3
4
  describe Locomotive::Steam::Decorators::TemplateDecorator do
4
5
 
@@ -30,6 +30,40 @@ describe Locomotive::Steam::ContentType do
30
30
 
31
31
  end
32
32
 
33
+ describe '#localized_names' do
34
+
35
+ subject { content_type.localized_names }
36
+
37
+ before {
38
+ expect(repository).to receive(:localized_names).and_return([])
39
+ expect(repository).to receive(:selects).and_return([instance_double('CategoryField', name: 'category')])
40
+ }
41
+
42
+ it { expect(subject).to eq ['category'] }
43
+
44
+ end
45
+
46
+
47
+ describe '#localized?' do
48
+
49
+ let(:names) { [] }
50
+
51
+ before { expect(repository).to receive(:localized_names).and_return(names) }
52
+
53
+ subject { content_type.localized? }
54
+
55
+ it { is_expected.to eq false }
56
+
57
+ context 'with one localized field' do
58
+
59
+ let(:names) { ['title'] }
60
+
61
+ it { is_expected.to eq true }
62
+
63
+ end
64
+
65
+ end
66
+
33
67
  describe '#default' do
34
68
 
35
69
  subject { content_type.fields_with_default }
@@ -72,30 +72,6 @@ describe Locomotive::Steam::Page do
72
72
  end
73
73
  end
74
74
 
75
- describe '#redirect?' do
76
-
77
- subject { page.redirect? }
78
-
79
- it { is_expected.to eq false }
80
-
81
- context 'redirect_url has been set' do
82
-
83
- let(:attributes) { { redirect: nil, redirect_url: 'http://www.google.fr' } }
84
-
85
- it { is_expected.to eq true }
86
-
87
- context 'but redirect is set to false' do
88
-
89
- let(:attributes) { { redirect: false, redirect_url: 'http://www.google.fr' } }
90
-
91
- it { is_expected.to eq false }
92
-
93
- end
94
-
95
- end
96
-
97
- end
98
-
99
75
  describe '#source' do
100
76
 
101
77
  let(:attributes) { { 'raw_template' => 'template code here' } }
@@ -70,14 +70,22 @@ describe Locomotive::Steam::Liquid::Drops::ContentEntry do
70
70
 
71
71
  describe '#errors' do
72
72
 
73
- let(:errors) { instance_double('Errors', messages: { title: ['not_blank'] }) }
73
+ let(:errors) { instance_double('Errors', messages: { title: ['not_blank'] }, blank?: false) }
74
74
 
75
75
  before do
76
- expect(entry).to receive(:errors).and_return(errors)
76
+ allow(entry).to receive(:errors).and_return(errors)
77
77
  end
78
78
 
79
79
  it { expect(subject.errors).to eq('title' => ['not_blank']) }
80
80
 
81
+ context 'no errors' do
82
+
83
+ let(:errors) { instance_double('Errors', blank?: true) }
84
+
85
+ it { expect(subject.errors).to eq(false) }
86
+
87
+ end
88
+
81
89
  end
82
90
 
83
91
  describe 'i18n' do
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  describe Locomotive::Steam::Liquid::Drops::Metafields do
4
4
 
5
- let(:metafields) { { 'my_namespace' => { 'analytics_id' => { 'default' => '42' }, 'street' => { 'en' => '7 Albert Camus Alley', 'fr' => '7 allée Albert Camus' } } } }
6
- let(:schema) { [ { 'name' => 'my_namespace', fields: [{ name: 'analytics_id', position: 1 }, { name: 'street', localized: true, position: 0 }, { name: 'country', :position => 2 }] }].as_json }
5
+ let(:metafields) { { 'my_namespace' => { 'visible' => { 'default' => '1' }, 'analytics_id' => { 'default' => '42' }, 'street' => { 'en' => '7 Albert Camus Alley', 'fr' => '7 allée Albert Camus' } } } }
6
+ let(:schema) { [ { 'name' => 'my_namespace', fields: [{ name: 'analytics_id', position: 1 }, { name: 'street', localized: true, position: 0 }, { name: 'country', :position => 2 }, { name: 'visible', type: 'boolean', position: 3 }] }].as_json }
7
7
  let(:site) { instance_double('Site', metafields: metafields, metafields_schema: schema) }
8
8
  let(:context) { ::Liquid::Context.new({}, {}, { locale: 'en' }) }
9
9
  let(:drop) { described_class.new(site).tap { |d| d.context = context } }
@@ -13,13 +13,13 @@ describe Locomotive::Steam::Liquid::Drops::Metafields do
13
13
  let(:namespace) { drop.before_method(:my_namespace).tap { |d| d.context = context } }
14
14
 
15
15
  it 'gives the number of the fields' do
16
- expect(namespace.size).to eq 3
16
+ expect(namespace.size).to eq 4
17
17
  end
18
18
 
19
19
  it 'iterates over the fields and keeps the order' do
20
20
  list = []
21
21
  namespace.each { |el| list << el['name'] }
22
- expect(list).to eq(['street', 'analytics_id', 'country'])
22
+ expect(list).to eq(['street', 'analytics_id', 'country', 'visible'])
23
23
  end
24
24
 
25
25
  end
@@ -46,6 +46,37 @@ describe Locomotive::Steam::Liquid::Drops::Metafields do
46
46
 
47
47
  end
48
48
 
49
+ context 'the field is a boolean' do
50
+
51
+ let(:boolean) { true }
52
+ let(:metafields) { { 'my_namespace' => { 'visible' => { 'default' => boolean } } } }
53
+
54
+ subject { namespace.before_method(:visible) }
55
+
56
+ it { is_expected.to eq true }
57
+
58
+ context '"true" is considered as true' do
59
+ let(:boolean) { 'true' }
60
+ it { is_expected.to eq true }
61
+ end
62
+
63
+ context '"1" is considered as true' do
64
+ let(:boolean) { '1' }
65
+ it { is_expected.to eq true }
66
+ end
67
+
68
+ context '"false" is considered as false' do
69
+ let(:boolean) { 'false' }
70
+ it { is_expected.to eq false }
71
+ end
72
+
73
+ context '"0" is considered as false' do
74
+ let(:boolean) { '0' }
75
+ it { is_expected.to eq false }
76
+ end
77
+
78
+ end
79
+
49
80
  context 'not a localized field' do
50
81
 
51
82
  context 'the value exists' do
@@ -63,8 +94,6 @@ describe Locomotive::Steam::Liquid::Drops::Metafields do
63
94
 
64
95
  end
65
96
 
66
-
67
-
68
97
  context "the value doesn't exist" do
69
98
 
70
99
  subject { namespace.before_method(:country) }
@@ -29,6 +29,23 @@ describe Locomotive::Steam::Liquid::Filters::Resize do
29
29
 
30
30
  it { is_expected.to match /\/steam\/dynamic\/.*\/240px-Metropolitan_railway_steam_locomotive_2781022036.png/ }
31
31
 
32
+ describe 'when imagemagick is not available' do
33
+
34
+ let(:input) {
35
+ double('image from liquid', url: 'http://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Metropolitan_railway_steam_locomotive_2781022036.png/240px-Metropolitan_railway_steam_locomotive_2781022036.png')
36
+ }
37
+
38
+ before do
39
+ image_resizer = @context.registers[:services].image_resizer
40
+ allow(image_resizer).to receive(:disabled?).and_return(true)
41
+ end
42
+
43
+ it 'returns the original url without resizing' do
44
+ is_expected.to eq 'http://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Metropolitan_railway_steam_locomotive_2781022036.png/240px-Metropolitan_railway_steam_locomotive_2781022036.png'
45
+ end
46
+
47
+ end
48
+
32
49
  end
33
50
 
34
51
  end
@@ -34,6 +34,13 @@ describe Locomotive::Steam::Liquid::Tags::WithScope do
34
34
 
35
35
  end
36
36
 
37
+ describe 'decode regexps with case-insensitive' do
38
+
39
+ let(:source) { "{% with_scope title: /like this/ix %}{% assign conditions = with_scope %}{% endwith_scope %}" }
40
+ it { expect(conditions['title']).to eq(/like this/ix) }
41
+
42
+ end
43
+
37
44
  describe 'decode content entry' do
38
45
 
39
46
  let(:entry) {
@@ -71,6 +78,14 @@ describe Locomotive::Steam::Liquid::Tags::WithScope do
71
78
 
72
79
  end
73
80
 
81
+ describe 'decode a regexp stored in a context variable, with case-insensitive' do
82
+
83
+ let(:assigns) { { 'my_regexp' => '/^hello world/ix' } }
84
+ let(:source) { "{% with_scope title: my_regexp %}{% assign conditions = with_scope %}{% endwith_scope %}" }
85
+ it { expect(conditions['title']).to eq(/^hello world/ix) }
86
+
87
+ end
88
+
74
89
  describe 'allow order_by option' do
75
90
 
76
91
  let(:source) { "{% with_scope order_by:\'name DESC\' %}{% assign conditions = with_scope %}{% endwith_scope %}" }
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ require_relative '../../../lib/locomotive/steam/middlewares/thread_safe'
4
+ require_relative '../../../lib/locomotive/steam/middlewares/helpers'
5
+ require_relative '../../../lib/locomotive/steam/middlewares/page'
6
+
7
+ describe Locomotive::Steam::Middlewares::Page do
8
+
9
+ let(:live_editing) { nil }
10
+ let(:published) { true }
11
+ let(:page_not_found) { instance_double('PageNotFound', not_found?: true) }
12
+ let(:page) { instance_double('Page', title: 'Hello world', fullpath: 'hello-world', not_found?: false, published?: published) }
13
+ let(:pages) { [page] }
14
+ let(:site) { instance_double('Site', default_locale: 'en') }
15
+ let(:service) { instance_double('PageFinder', match: pages) }
16
+ let(:url) { 'http://models.example.com' }
17
+ let(:app) { ->(env) { [200, env, 'app'] } }
18
+ let(:middleware) { described_class.new(app) }
19
+
20
+ subject do
21
+ env = env_for(url, 'steam.site' => site)
22
+ env['steam.path'] = 'hello-world'
23
+ env['steam.locale'] = 'en'
24
+ env['steam.request'] = Rack::Request.new(env)
25
+ env['steam.live_editing'] = live_editing
26
+ code, env = middleware.call(env)
27
+ env['steam.page']
28
+ end
29
+
30
+ before do
31
+ allow_any_instance_of(described_class).to receive(:page_finder).and_return(service)
32
+ allow(service).to receive(:find).with('404').and_return(page_not_found)
33
+ end
34
+
35
+ it { is_expected.to eq page }
36
+
37
+ context "page doesn't exist" do
38
+
39
+ let(:pages) { [] }
40
+
41
+ it { is_expected.to eq page_not_found }
42
+
43
+ end
44
+
45
+ context 'page is unpublished' do
46
+
47
+ let(:published) { false }
48
+
49
+ it { is_expected.to eq page_not_found }
50
+
51
+ context 'the live editing mode is on' do
52
+
53
+ let(:live_editing) { true }
54
+
55
+ it 'has to display it' do
56
+ is_expected.to eq page
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -8,9 +8,7 @@ describe Locomotive::Steam::Middlewares::Renderer do
8
8
 
9
9
  let(:app) { ->(env) { [200, env, 'app'] }}
10
10
 
11
- let :middleware do
12
- Locomotive::Steam::Middlewares::Renderer.new(app)
13
- end
11
+ let(:middleware) { described_class.new(app) }
14
12
 
15
13
  describe 'missing 404 page' do
16
14
 
@@ -21,7 +19,7 @@ describe Locomotive::Steam::Middlewares::Renderer do
21
19
  middleware.call env_for('http://www.example.com', { 'steam.page' => nil, 'steam.locale' => locale, 'steam.site' => site })
22
20
  end
23
21
 
24
- specify 'return 200' do
22
+ specify 'return 404' do
25
23
  code, headers, response = subject
26
24
  expect(code).to eq(404)
27
25
  expect(response).to eq(["Your 404 page is missing. Please create it."])
@@ -6,19 +6,21 @@ require_relative '../../../lib/locomotive/steam/middlewares/sitemap'
6
6
 
7
7
  describe Locomotive::Steam::Middlewares::Sitemap do
8
8
 
9
+ let(:site) { instance_double('Site', locales: ['en', 'fr'], default_locale: 'en') }
9
10
  let(:pages) { [] }
10
11
  let(:page_repository) { instance_double('PageRepository', published: pages) }
11
12
  let(:app) { ->(env) { [200, env, 'app'] }}
12
13
  let(:middleware) { described_class.new(app) }
13
14
 
14
15
  before do
16
+ allow_any_instance_of(described_class).to receive(:site).and_return(site)
15
17
  allow_any_instance_of(described_class).to receive(:base_url).and_return('http://localhost/')
16
18
  allow_any_instance_of(described_class).to receive(:page_repository).and_return(page_repository)
17
19
  end
18
20
 
19
21
  describe '#call' do
20
22
 
21
- let(:env) { { 'PATH_INFO' => '/sitemap.xml', 'steam.page' => nil } }
23
+ let(:env) { { 'PATH_INFO' => '/sitemap.xml', 'steam.page' => nil, 'steam.site' => site } }
22
24
  subject { middleware.call(env) }
23
25
 
24
26
  describe 'no pages' do
@@ -39,6 +41,44 @@ describe Locomotive::Steam::Middlewares::Sitemap do
39
41
 
40
42
  end
41
43
 
44
+ describe '#build_templatized_page_xml?' do
45
+
46
+ let(:localized) { true }
47
+ let(:source) { '<h1>{{ post.title }}</h1>' }
48
+ let(:page) { instance_double('TemplatePage', source: source) }
49
+ let(:content_type) { instance_double('Post', localized?: localized) }
50
+ let(:locale) { 'fr' }
51
+
52
+ subject { middleware.send(:build_templatized_page_xml?, page, content_type, locale) }
53
+
54
+ it { is_expected.to eq true }
55
+
56
+ context 'current locale is equals to the site default locale' do
57
+
58
+ let(:locale) { 'en' }
59
+
60
+ it { is_expected.to eq true }
61
+
62
+ end
63
+
64
+ context 'the content type is not localized' do
65
+
66
+ let(:localized) { false }
67
+
68
+ it { is_expected.to eq true }
69
+
70
+ context 'the page has the same liquid template in all the locales' do
71
+
72
+ let(:source) { '' }
73
+
74
+ it { is_expected.to eq false }
75
+
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+
42
82
  end
43
83
 
44
84
  end
@@ -75,6 +75,16 @@ describe Locomotive::Steam::ExternalAPIService do
75
75
  end
76
76
  end
77
77
 
78
+ describe 'sets authorization header' do
79
+
80
+ let(:url) { 'http://blog.locomotiveapp.org' }
81
+ let(:options) { { header_auth: 'letmein' } }
82
+ it do
83
+ expect(service.class).to receive(:get).with('/', { base_uri: 'http://blog.locomotiveapp.org', headers: { 'Authorization' => 'letmein' } }).and_return(response)
84
+ subject
85
+ end
86
+ end
87
+
78
88
  end
79
89
 
80
90
  end
@@ -14,7 +14,7 @@ describe Locomotive::Steam::ImageResizerService do
14
14
  subject { service.resize(input, geometry) }
15
15
 
16
16
  describe 'no resizer' do
17
- it { is_expected.to eq nil }
17
+ it { is_expected.to eq 'http://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Metropolitan_railway_steam_locomotive_2781022036.png/240px-Metropolitan_railway_steam_locomotive_2781022036.png' }
18
18
  end
19
19
 
20
20
  describe 'DragonFly' do
@@ -23,12 +23,12 @@ describe Locomotive::Steam::ImageResizerService do
23
23
 
24
24
  describe 'no imagemagick' do
25
25
  before { expect(resizer.plugins).to receive(:[]).with(:imagemagick).and_return(nil) }
26
- it { is_expected.to eq nil }
26
+ it { is_expected.to eq 'http://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Metropolitan_railway_steam_locomotive_2781022036.png/240px-Metropolitan_railway_steam_locomotive_2781022036.png' }
27
27
  end
28
28
 
29
29
  describe 'no geometry' do
30
30
  let(:geometry) { '' }
31
- it { is_expected.to eq nil }
31
+ it { is_expected.to eq 'http://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Metropolitan_railway_steam_locomotive_2781022036.png/240px-Metropolitan_railway_steam_locomotive_2781022036.png' }
32
32
  end
33
33
 
34
34
  it { is_expected.to match /\/steam\/dynamic\/.*\/240px-Metropolitan_railway_steam_locomotive_2781022036.png/ }