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
@@ -11,6 +11,7 @@ module Locomotive::Steam
11
11
  ENTRY_SUBMISSION_REGEXP = /^\/entry_submissions\/(\w+)/o
12
12
  SUBMITTED_TYPE_PARAM = 'submitted_type_slug'
13
13
  SUBMITTED_PARAM = 'submitted_entry_slug'
14
+ CONTENT_TYPE_PARAM = 'content_type_slug'
14
15
 
15
16
  def _call
16
17
  # we didn't go through the locale middleware yet,
@@ -72,8 +73,26 @@ module Locomotive::Steam
72
73
  end
73
74
 
74
75
  def entry_to_query_string(entry)
75
- type, slug = entry.content_type_slug, entry._slug
76
- "#{SUBMITTED_TYPE_PARAM}=#{type}&#{SUBMITTED_PARAM}=#{slug}"
76
+ service_params = [
77
+ services.csrf_protection.field,
78
+ CONTENT_TYPE_PARAM,
79
+ SUBMITTED_TYPE_PARAM,
80
+ SUBMITTED_PARAM,
81
+ 'success_callback',
82
+ 'error_callback',
83
+ 'content',
84
+ 'entry'
85
+ ]
86
+
87
+ [].tap do |list|
88
+ params.each do |key, value|
89
+ next if service_params.include?(key)
90
+ list << "#{key}=#{value}"
91
+ end
92
+
93
+ list << "#{SUBMITTED_TYPE_PARAM}=#{entry.content_type_slug}"
94
+ list << "#{SUBMITTED_PARAM}=#{entry._slug}"
95
+ end.join('&')
77
96
  end
78
97
 
79
98
  def with_locale(&block)
@@ -109,8 +128,8 @@ module Locomotive::Steam
109
128
  # or from the presence of the content_type_slug param (model_form tag).
110
129
  #
111
130
  def get_content_type_slug
112
- if request.post? && (request.path_info =~ ENTRY_SUBMISSION_REGEXP || params[:content_type_slug])
113
- $1 || params[:content_type_slug]
131
+ if request.post? && (request.path_info =~ ENTRY_SUBMISSION_REGEXP || params[CONTENT_TYPE_PARAM])
132
+ $1 || params[CONTENT_TYPE_PARAM]
114
133
  end
115
134
  end
116
135
 
@@ -26,11 +26,21 @@ module Locomotive::Steam
26
26
  protected
27
27
 
28
28
  def fetch_page
29
- services.page_finder.match(path).tap do |pages|
29
+ page = page_finder.match(path).tap do |pages|
30
30
  if pages.size > 1
31
31
  self.log "Found multiple pages: #{pages.map(&:title).join(', ')}"
32
32
  end
33
- end.first || services.page_finder.find('404')
33
+ end.first
34
+
35
+ if page && (page.published? || page.not_found? || live_editing?)
36
+ page
37
+ else
38
+ page_finder.find('404')
39
+ end
40
+ end
41
+
42
+ def page_finder
43
+ services.page_finder
34
44
  end
35
45
 
36
46
  end
@@ -16,7 +16,7 @@ module Locomotive::Steam
16
16
  private
17
17
 
18
18
  def render_page
19
- if page.redirect_url.presence
19
+ if page.redirect?
20
20
  redirect_to(page.redirect_url, page.redirect_type)
21
21
  else
22
22
  content = parse_and_render_liquid
@@ -73,7 +73,7 @@ module Locomotive::Steam
73
73
  'today' => Date.today,
74
74
  'mode' => Locomotive::Steam.configuration.mode,
75
75
  'wagon' => Locomotive::Steam.configuration.mode == :test,
76
- 'live_editing' => !!env['steam.live_editing']
76
+ 'live_editing' => live_editing?
77
77
  }
78
78
  end
79
79
 
@@ -98,14 +98,15 @@ module Locomotive::Steam
98
98
 
99
99
  def _request_liquid_assigns
100
100
  {
101
- 'path' => request.path,
101
+ 'base_url' => request.base_url,
102
102
  'fullpath' => request.fullpath,
103
- 'url' => request.url,
104
103
  'ip_address' => request.ip,
104
+ 'mounted_on' => mounted_on,
105
+ 'path' => request.path,
105
106
  'post?' => request.post?,
106
- 'base_url' => request.base_url,
107
+ 'referer' => request.referer,
108
+ 'url' => request.url,
107
109
  'user_agent' => request.user_agent,
108
- 'mounted_on' => mounted_on
109
110
  }
110
111
  end
111
112
 
@@ -53,6 +53,8 @@ module Locomotive::Steam
53
53
  def build_templatized_page_xml(page, locale)
54
54
  content_type = repositories.content_type.find(page.content_type_id)
55
55
 
56
+ return nil unless build_templatized_page_xml?(page, content_type, locale)
57
+
56
58
  repositories.content_entry.with(content_type).all.map do |entry|
57
59
  _entry = Locomotive::Steam::Decorators::I18nDecorator.new(entry, locale)
58
60
 
@@ -88,6 +90,15 @@ module Locomotive::Steam
88
90
  services.url_builder.url_for(page, locale)
89
91
  end
90
92
 
93
+ def build_templatized_page_xml?(page, content_type, locale)
94
+ return true if content_type.localized? || default_locale == locale
95
+
96
+ # does the templatized page have the same source
97
+ # (liquid template) as in the default locale?
98
+ # If so, no need to add a xml entry for this page
99
+ !page.source.blank?
100
+ end
101
+
91
102
  def base_url
92
103
  "#{request.scheme}://#{request.host_with_port}"
93
104
  end
@@ -61,6 +61,10 @@ module Locomotive::Steam::Middlewares
61
61
  @params ||= self.request.params.with_indifferent_access
62
62
  end
63
63
 
64
+ def live_editing?
65
+ !!env['steam.live_editing']
66
+ end
67
+
64
68
  end
65
69
 
66
70
  end
@@ -31,7 +31,7 @@ module Locomotive::Steam
31
31
  @translations = (if translations.respond_to?(:fetch)
32
32
  translations
33
33
  else
34
- Hash.new { translations }
34
+ Hash.new(translations)
35
35
  end).with_indifferent_access
36
36
  end
37
37
 
@@ -58,7 +58,9 @@ module Locomotive
58
58
  end
59
59
 
60
60
  def localized_names
61
- query { where(localized: true) }.all.map(&:name)
61
+ query { where(localized: true) }.all.map do |field|
62
+ field.type == :select ? [field.name, "#{field.name}_id"] : field.name
63
+ end.flatten
62
64
  end
63
65
 
64
66
  def default
@@ -1,4 +1,3 @@
1
- require 'haml'
2
1
  require 'mimetype_fu'
3
2
  require 'mime-types'
4
3
  require 'mime/types'
@@ -16,6 +16,10 @@ module Locomotive
16
16
  username, password = options.delete(:username), options.delete(:password)
17
17
  options[:basic_auth] = { username: username, password: password } if username
18
18
 
19
+ # authorization header ?
20
+ header_auth = options.delete(:header_auth)
21
+ options[:headers] = { 'Authorization' => header_auth } if header_auth
22
+
19
23
  perform_request_to(path, options)
20
24
  end
21
25
 
@@ -37,7 +41,10 @@ module Locomotive
37
41
 
38
42
  # sanitize the options
39
43
  options[:format] = options[:format].gsub(/[\'\"]/, '').to_sym if options.has_key?(:format)
40
- options[:headers] = { 'User-Agent' => 'LocomotiveCMS' } if options[:with_user_agent]
44
+ if options[:with_user_agent]
45
+ user_agent = { 'User-Agent' => 'LocomotiveCMS' }
46
+ options[:headers] ? options[:headers].merge!(user_agent) : options[:headers] = user_agent
47
+ end
41
48
 
42
49
  response = self.class.get(path, options)
43
50
  parsed_response = response.parsed_response
@@ -6,7 +6,7 @@ module Locomotive
6
6
  attr_accessor_initialize :resizer, :asset_path
7
7
 
8
8
  def resize(source, geometry)
9
- return nil if disabled? || geometry.blank?
9
+ return get_url_or_path(source) if disabled? || geometry.blank?
10
10
 
11
11
  if file = fetch_file(source)
12
12
  file.thumb(geometry).url
@@ -27,6 +27,10 @@ module Locomotive
27
27
 
28
28
  private
29
29
 
30
+ def decorate(&block)
31
+ super(Decorators::PageDecorator, &block)
32
+ end
33
+
30
34
  # Instead of hitting the DB each time we want a page from its handle,
31
35
  # just get all the handles at once and cache the result. (up to 20% boost)
32
36
  #
@@ -3,6 +3,6 @@
3
3
  # 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
4
4
  module Locomotive
5
5
  module Steam
6
- VERSION = '1.2.0.beta1'
6
+ VERSION = '1.2.0.rc1'
7
7
  end
8
8
  end
@@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.add_development_dependency 'bundler', '~> 1.7'
19
19
  spec.add_development_dependency 'rake', '~> 10.4.2'
20
20
 
21
- spec.add_development_dependency 'mongo', '~> 2.2.3'
22
- spec.add_development_dependency 'origin', '~> 2.1.1'
21
+ spec.add_development_dependency 'mongo', '~> 2.2.7'
22
+ spec.add_development_dependency 'origin', '~> 2.2.0'
23
23
 
24
- spec.add_dependency 'nokogiri', '~> 1.6.7.2'
24
+ spec.add_dependency 'nokogiri', '~> 1.6.8'
25
25
  spec.add_dependency 'sanitize', '~> 4.0.1'
26
26
  spec.add_dependency 'morphine', '~> 0.1.1'
27
27
  spec.add_dependency 'httparty', '~> 0.13.6'
@@ -40,8 +40,7 @@ Gem::Specification.new do |spec|
40
40
  spec.add_dependency 'autoprefixer-rails', '~> 6.3.3.1'
41
41
 
42
42
  spec.add_dependency 'kramdown', '~> 1.10.0'
43
- spec.add_dependency 'RedCloth', '~> 4.2.9'
44
- spec.add_dependency 'haml', '~> 4.0.6'
43
+ spec.add_dependency 'RedCloth', '~> 4.3.2'
45
44
  spec.add_dependency 'mimetype-fu', '~> 0.1.2'
46
45
  spec.add_dependency 'mime-types', '~> 2.6.1'
47
46
  spec.add_dependency 'duktape', '~> 1.3.0.6'
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: All the pages
3
3
  listed: false
4
- published: false
4
+ published: true
5
5
  ---
6
6
  {% extends parent %}
7
7
  {% block content %}
@@ -10,4 +10,7 @@ published: false
10
10
  <li>{{ page.title }}</li>
11
11
  {% endfor %}
12
12
  </ul>
13
+
14
+ <!-- TEST -->{{ site.index.children | map: 'title' | join: " - " }}<!-- TEST -->
15
+
13
16
  {% endblock %}
@@ -13,10 +13,17 @@ position: 4
13
13
  Ut imperdiet velit eu metus semper tristique. Vivamus risus nisi, tincidunt et euismod a, auctor pretium eros. Vestibulum sed magna et velit pulvinar euismod. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sed velit quis nisl blandit vulputate id non tortor. Mauris nec placerat massa. Vivamus sed odio non ligula pharetra pretium. Ut convallis, purus et lobortis suscipit, mauris orci ullamcorper lectus, nec vulputate turpis mauris sed augue. Maecenas faucibus ultricies nisl, non ullamcorper justo bibendum nec. Duis vitae mauris condimentum risus commodo mattis vel sed libero. Fusce diam elit, porta id vestibulum ut, aliquet mattis neque.
14
14
  {% endeditable_long_text %}
15
15
 
16
+ {% if message.errors %}
17
+ .text
18
+ %p Form with errors
19
+ {% endif %}
20
+
16
21
  %form#contactform{ :name => 'contact', :action => '{{ contents.messages.public_submission_url }}.json', :method => 'post' }
17
22
  / %input{ type: 'hidden', name: 'success_callback', value: '/events' }
18
23
  / %input{ type: 'hidden', name: 'error_callback', value: '/contact' }
19
24
 
25
+ %input{ type: 'hidden', name: 'some_variable', value: '42' }
26
+
20
27
  %p
21
28
  %label{ :for => 'name' } Name
22
29
  %input{ :type => 'text', :id => 'name', :name => 'content[name]', :placeholder => 'First and last name', :tabindex => '1', required: 'required', value: '{{ message.name }}' }
@@ -51,4 +58,4 @@ position: 4
51
58
  });
52
59
  });
53
60
 
54
- {% endblock %}
61
+ {% endblock %}
@@ -5,8 +5,15 @@ position: 5
5
5
 
6
6
  {% block content %}
7
7
 
8
+ {% if message.errors %}
9
+ .text
10
+ %p Form with errors
11
+ {% endif %}
12
+
8
13
  %p Thank you {{ message.name }} !
9
14
 
15
+ %p Some variable: {{ params.some_variable }}
16
+
10
17
  #events.unit.size2of3
11
18
  %h2 Upcoming events
12
19
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Page to test the nav tag with a high depth
3
3
  listed: false
4
- published: false
4
+ published: true
5
5
  ---
6
- {% nav 'site', depth: 2 %}
6
+ {% nav 'site', depth: 2 %}
@@ -5,7 +5,9 @@
5
5
  en: john posted a new post
6
6
  fr: phrase FR
7
7
  date: 2009/11/16
8
- category: General
8
+ category:
9
+ en: General
10
+ fr: Général
9
11
  - "Update #5":
10
12
  title:
11
13
  fr: "Mise a jour #5"
@@ -45,4 +47,4 @@
45
47
  en: added some free stuff
46
48
  fr: phrase FR
47
49
  date: 2009/05/12
48
- category: General
50
+ category: General
@@ -78,6 +78,10 @@ describe 'ContactForm' do
78
78
  expect(response.status).to eq 200
79
79
  end
80
80
 
81
+ it 'displays a global error message' do
82
+ expect(response.body.to_s).to include "Form with errors"
83
+ end
84
+
81
85
  it 'displays errors' do
82
86
  expect(response.body.to_s).to include "can't be blank"
83
87
  end
@@ -104,6 +108,10 @@ describe 'ContactForm' do
104
108
  expect(response.status).to eq 200
105
109
  end
106
110
 
111
+ it "doesn't display a global error message" do
112
+ expect(response.body.to_s).not_to include "Form with errors"
113
+ end
114
+
107
115
  it 'displays a success message' do
108
116
  expect(response.body.to_s).to include 'Thank you John'
109
117
  end
@@ -130,6 +138,7 @@ describe 'ContactForm' do
130
138
  let(:url) { '/events' }
131
139
  let(:params) { {
132
140
  'content_type_slug' => 'messages',
141
+ 'some_variable' => '42',
133
142
  'entry' => { 'name' => 'John', 'email' => 'j@doe.net', 'message' => 'Bla bla' } } }
134
143
  let(:response) { post_contact_form(url, params) }
135
144
  let(:status) { response.status }
@@ -160,6 +169,10 @@ describe 'ContactForm' do
160
169
  expect(response.body.to_s).to include 'Thank you John'
161
170
  end
162
171
 
172
+ it 'stores hidden fields from the form' do
173
+ expect(response.body.to_s).to include 'Some variable: 42'
174
+ end
175
+
163
176
  end
164
177
 
165
178
  context 'in a different locale' do
@@ -29,6 +29,10 @@ describe Locomotive::Steam::Server do
29
29
  is_expected.to include('<li>A song template</li>')
30
30
  end
31
31
 
32
+ it 'lists all the pages from the site liquid drop' do
33
+ is_expected.to include('<!-- TEST -->About Us - Music - Store - Contact Us - Events - Basic page - A sample contest - Various uses of the with_scope tag - Grunge leaders - Tags - Unlisted pages - Archives - All the pages - Layouts - Songs<!-- TEST -->')
34
+ end
35
+
32
36
  describe 'with wrapper' do
33
37
 
34
38
  subject { get '/tags/nav'; last_response.body }
@@ -21,7 +21,7 @@ describe Locomotive::Steam::Server do
21
21
 
22
22
  it 'checks if it looks valid' do
23
23
  expect(Nokogiri::XML(subject).errors.empty?).to eq true
24
- expect(subject.scan(/<url>/).size).to eq 46
24
+ expect(subject.scan(/<url>/).size).to eq 40
25
25
  expect(subject).to match("<loc>http://example.org/songs/song-number-2/band</loc>")
26
26
  expect(subject).to match((<<-EOF
27
27
  <url>
@@ -36,7 +36,7 @@ describe Locomotive::Steam::Server do
36
36
  context 'existing sitemap page' do
37
37
 
38
38
  let(:template) { %{<?xml version="1.0" encoding="utf-8"?>OK</xml>} }
39
- let(:page) { instance_double('Page', liquid_source: template, templatized?: false, redirect_url: false, to_liquid: template, not_found?: false, response_type: 'application/xml') }
39
+ let(:page) { instance_double('Page', liquid_source: template, templatized?: false, redirect?: false, to_liquid: template, not_found?: false, response_type: 'application/xml') }
40
40
  let(:env) { { 'steam.page' => page } }
41
41
 
42
42
  it 'renders the existing sitemap page' do
@@ -23,6 +23,8 @@ module Spec
23
23
  end
24
24
 
25
25
  def run_server
26
+ require 'haml'
27
+
26
28
  output = ENV['STEAM_VERBOSE'] ? nil : File.join(default_fixture_site_path, 'log/steam.log')
27
29
  setup_common(output)
28
30
 
@@ -45,6 +45,23 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentEntry do
45
45
 
46
46
  end
47
47
 
48
+ context 'a content type with a localized field' do
49
+
50
+ let(:options_scope) { instance_double('Scope', :locale= => true) }
51
+ let(:options) { instance_double('SelectOptionsRepository', scope: options_scope) }
52
+ let(:field) { instance_double('Field', name: 'category', type: :select, localized: true, select_options: options) }
53
+ let(:content_type) { instance_double('Updates', slug: 'updates', select_fields: [field], association_fields: [], file_fields: []) }
54
+
55
+ it 'adds a new localized attribute for the foreign key' do
56
+ option = instance_double('Option', _id: 'General')
57
+ allow(options).to receive(:by_name).with('General').and_return(option)
58
+ allow(options).to receive(:by_name).with('Général').and_return(option)
59
+ expect(subject.last[:category_id]).to eq({ en: 'General', fr: 'General' })
60
+ expect(subject.last[:category]).to eq nil
61
+ end
62
+
63
+ end
64
+
48
65
  context 'a content type with a file field' do
49
66
 
50
67
  let(:field) { instance_double('Field', name: 'cover', type: :file) }