locomotivecms_steam 1.6.0.beta1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/Gemfile.lock +79 -39
  4. data/bin/steam.rb +1 -7
  5. data/docker-compose.yml +4 -0
  6. data/lib/locomotive/steam/configuration.rb +13 -0
  7. data/lib/locomotive/steam/entities/site.rb +1 -0
  8. data/lib/locomotive/steam/liquid/tags/concerns/attributes.rb +97 -10
  9. data/lib/locomotive/steam/liquid/tags/concerns/path.rb +23 -4
  10. data/lib/locomotive/steam/liquid/tags/consume.rb +2 -2
  11. data/lib/locomotive/steam/liquid/tags/editable/base.rb +4 -4
  12. data/lib/locomotive/steam/liquid/tags/global_section.rb +1 -1
  13. data/lib/locomotive/steam/liquid/tags/inherited_block.rb +2 -3
  14. data/lib/locomotive/steam/liquid/tags/section.rb +4 -4
  15. data/lib/locomotive/steam/liquid/tags/snippet.rb +10 -0
  16. data/lib/locomotive/steam/liquid/tags/with_scope.rb +16 -24
  17. data/lib/locomotive/steam/middlewares/auth.rb +9 -5
  18. data/lib/locomotive/steam/middlewares/concerns/auth_helpers.rb +1 -1
  19. data/lib/locomotive/steam/middlewares/concerns/helpers.rb +5 -1
  20. data/lib/locomotive/steam/middlewares/concerns/rendering.rb +1 -1
  21. data/lib/locomotive/steam/middlewares/locale.rb +5 -5
  22. data/lib/locomotive/steam/middlewares/logging.rb +2 -4
  23. data/lib/locomotive/steam/middlewares/page.rb +4 -4
  24. data/lib/locomotive/steam/middlewares/path.rb +7 -1
  25. data/lib/locomotive/steam/middlewares/private_access.rb +2 -2
  26. data/lib/locomotive/steam/middlewares/templatized_page.rb +1 -1
  27. data/lib/locomotive/steam/middlewares/timezone.rb +1 -1
  28. data/lib/locomotive/steam/models/i18n_field.rb +2 -2
  29. data/lib/locomotive/steam/models/mapper.rb +2 -1
  30. data/lib/locomotive/steam/services/content_entry_service.rb +12 -0
  31. data/lib/locomotive/steam/version.rb +1 -1
  32. data/lib/locomotive/steam.rb +7 -0
  33. data/locomotivecms_steam.gemspec +3 -1
  34. data/spec/fixtures/default/app/content_types/accounts.yml +3 -0
  35. data/spec/spec_helper.rb +1 -1
  36. data/spec/support/helpers.rb +2 -4
  37. data/spec/unit/liquid/tags/paginate_spec.rb +1 -1
  38. data/spec/unit/liquid/tags/with_scope_spec.rb +59 -0
  39. data/spec/unit/middlewares/cache_spec.rb +4 -4
  40. data/spec/unit/middlewares/path_spec.rb +70 -0
  41. metadata +45 -9
@@ -33,28 +33,37 @@ module Locomotive
33
33
  'x' => Regexp::EXTENDED
34
34
  }.freeze
35
35
 
36
+ OPERATORS = %w(all exists gt gte in lt lte ne nin size near within)
37
+
38
+ SYMBOL_OPERATORS_REGEXP = /(\w+\.(#{OPERATORS.join('|')})){1}\s*\:/o
39
+
36
40
  attr_reader :attributes, :attributes_var_name
37
41
 
38
42
  def initialize(tag_name, markup, options)
39
43
  super
40
44
 
45
+ # convert symbol operators into valid ruby code
46
+ markup.gsub!(SYMBOL_OPERATORS_REGEXP, ':"\1" =>')
47
+
41
48
  # simple hash?
42
49
  parse_attributes(markup) { |value| parse_attribute(value) }
43
50
 
44
- if attributes.empty? && markup =~ SingleVariable
51
+ if raw_attributes.empty? && markup =~ SingleVariable
45
52
  # alright, maybe we'vot got a single variable built
46
53
  # with the Action liquid tag instead?
47
54
  @attributes_var_name = Regexp.last_match(1)
48
55
  end
49
56
 
50
- if attributes.empty? && attributes_var_name.blank?
57
+ if raw_attributes.empty? && attributes_var_name.blank?
51
58
  raise ::Liquid::SyntaxError.new("Syntax Error in 'with_scope' - Valid syntax: with_scope <name_1>: <value_1>, ..., <name_n>: <value_n>")
52
59
  end
53
60
  end
54
61
 
55
62
  def render(context)
56
63
  context.stack do
57
- context['with_scope'] = self.evaluate_attributes(context)
64
+ @raw_attributes = context[attributes_var_name] || {} if attributes_var_name.present?
65
+ @raw_attributes.transform_keys! { |key| key.to_s == '_permalink' ? '_slug' : key.to_s }
66
+ context['with_scope'] = evaluate_attributes(context)
58
67
 
59
68
  # for now, no content type is assigned to this with_scope
60
69
  context['with_scope_content_type'] = false
@@ -68,7 +77,7 @@ module Locomotive
68
77
  def parse_attribute(value)
69
78
  case value
70
79
  when StrictRegexpFragment
71
- # let the cast_value attribute create the Regexp (done during the rendering phase)
80
+ # let the evaluate_value attribute create the Regexp (done during the rendering phase)
72
81
  value
73
82
  when ArrayFragment
74
83
  $1.split(',').map { |_value| parse_attribute(_value) }
@@ -77,28 +86,11 @@ module Locomotive
77
86
  end
78
87
  end
79
88
 
80
- def evaluate_attributes(context)
81
- @attributes = context[attributes_var_name] || {} if attributes_var_name.present?
82
-
83
- HashWithIndifferentAccess.new.tap do |hash|
84
- attributes.each do |key, value|
85
- # _slug instead of _permalink
86
- _key = key.to_s == '_permalink' ? '_slug' : key.to_s
87
-
88
- # evaluate the value if possible before casting it
89
- _value = value.is_a?(::Liquid::VariableLookup) ? context.evaluate(value) : value
90
-
91
- hash[_key] = cast_value(context, _value)
92
- end
93
- end
94
- end
95
-
96
- def cast_value(context, value)
97
- case value
98
- when Array then value.map { |_value| cast_value(context, _value) }
89
+ def evaluate_value(context, value, lax: false)
90
+ _value = super
91
+ case _value
99
92
  when StrictRegexpFragment then create_regexp($1, $2)
100
93
  else
101
- _value = context.evaluate(value)
102
94
  _value.respond_to?(:_id) ? _value.send(:_source) : _value
103
95
  end
104
96
  end
@@ -30,7 +30,12 @@ module Locomotive::Steam
30
30
  private
31
31
 
32
32
  def sign_up(options)
33
- return if authenticated? || !is_recaptcha_valid?(options.type, options.recaptcha_response)
33
+ return if authenticated?
34
+
35
+ if !is_recaptcha_valid?(options.type, options.recaptcha_response)
36
+ append_message(:invalid_recaptcha_code)
37
+ return
38
+ end
34
39
 
35
40
  status, entry = services.auth.sign_up(options, default_liquid_context, request)
36
41
 
@@ -101,7 +106,7 @@ module Locomotive::Steam
101
106
  end
102
107
 
103
108
  def append_message(message)
104
- log "[Auth] status message = #{message.inspect}"
109
+ debug_log "[Auth] status message = #{message.inspect}"
105
110
 
106
111
  message ||= 'error'
107
112
  liquid_assigns["auth_#{message}"] = "auth_#{message}"
@@ -158,7 +163,7 @@ module Locomotive::Steam
158
163
  end
159
164
 
160
165
  def from
161
- smtp_config['sender'] || 'support@locomotivecms.com'
166
+ smtp_config['sender'] || smtp_config['from'] || 'support@locomotivecms.com'
162
167
  end
163
168
 
164
169
  def subject
@@ -182,7 +187,7 @@ module Locomotive::Steam
182
187
  end
183
188
 
184
189
  def recaptcha_response
185
- params["g-recaptcha-response"]
190
+ params['g-recaptcha-response']
186
191
  end
187
192
 
188
193
  def smtp
@@ -213,7 +218,6 @@ module Locomotive::Steam
213
218
  end
214
219
  end
215
220
 
216
-
217
221
  end
218
222
 
219
223
  end
@@ -19,7 +19,7 @@ module Locomotive::Steam
19
19
 
20
20
  env['steam.authenticated_entry'] = nil if entry.nil?
21
21
 
22
- log "[Auth] authenticated #{type.to_s.singularize} ##{entry&._id.to_s}"
22
+ debug_log "[Auth] authenticated #{type.to_s.singularize} ##{entry&._id.to_s}"
23
23
 
24
24
  liquid_assigns["current_#{type.singularize}"] = entry
25
25
  end
@@ -40,7 +40,7 @@ module Locomotive::Steam
40
40
  def redirect_to(location, type = 301)
41
41
  _location = mounted_on && !location.starts_with?(mounted_on) && (location =~ Locomotive::Steam::IsHTTP).nil? ? "#{mounted_on}#{location}" : location
42
42
 
43
- self.log "Redirected to #{_location}".blue
43
+ self.debug_log "Redirected to #{_location}".blue
44
44
 
45
45
  headers = { 'Content-Type' => HTML_CONTENT_TYPE, 'Location' => _location }
46
46
  inject_cookies(headers)
@@ -83,6 +83,10 @@ module Locomotive::Steam
83
83
  Locomotive::Common::Logger.info (' ' * offset) + msg
84
84
  end
85
85
 
86
+ def debug_log(msg, offset = 2)
87
+ Locomotive::Common::Logger.debug (' ' * offset) + msg
88
+ end
89
+
86
90
  end
87
91
  end
88
92
  end
@@ -28,7 +28,7 @@ module Locomotive::Steam
28
28
  "Your 404 page is missing."
29
29
  end) + " Please create it."
30
30
 
31
- log "[Warning] #{message}".red
31
+ debug_log "[Warning] #{message}".red
32
32
 
33
33
  render_response(message, 404)
34
34
  end
@@ -23,7 +23,7 @@ module Locomotive::Steam
23
23
 
24
24
  set_locale_cookie
25
25
 
26
- log "Locale used: #{locale.upcase}"
26
+ debug_log "Locale used: #{locale.upcase}"
27
27
 
28
28
  I18n.with_locale(locale) do
29
29
  self.next
@@ -48,7 +48,7 @@ module Locomotive::Steam
48
48
 
49
49
  def locale_from_params
50
50
  params[:locale]&.to_sym.tap do |locale|
51
- log 'Locale extracted from the params' unless locale.blank?
51
+ debug_log 'Locale extracted from the params' unless locale.blank?
52
52
  end
53
53
  end
54
54
 
@@ -62,7 +62,7 @@ module Locomotive::Steam
62
62
  env['steam.path'] = path.gsub(/^\/#{$1 + $2}/, '/')
63
63
  env['steam.locale_in_path'] = true
64
64
 
65
- log 'Locale extracted from the path'
65
+ debug_log'Locale extracted from the path'
66
66
 
67
67
  locale.to_sym
68
68
  end
@@ -73,14 +73,14 @@ module Locomotive::Steam
73
73
  .sort { |a, b| b[1] <=> a[1] }
74
74
  .map { |lang, _| lang[0..1].to_sym }
75
75
  .find { |lang| locales.include?(lang) }.tap do |locale|
76
- log 'Locale extracted from the header' unless locale.blank?
76
+ debug_log 'Locale extracted from the header' unless locale.blank?
77
77
  end
78
78
  end
79
79
 
80
80
  def locale_from_cookie
81
81
  if locale = services.cookie.get(cookie_key_name)
82
82
 
83
- log 'Locale extracted from the cookie'
83
+ debug_log 'Locale extracted from the cookie'
84
84
 
85
85
  locale.to_sym
86
86
  end
@@ -14,10 +14,8 @@ module Locomotive::Steam
14
14
 
15
15
  log "Started #{env['REQUEST_METHOD'].upcase} \"#{env['PATH_INFO']}\" at #{now}".light_white, 0
16
16
 
17
- if Locomotive::Steam.configuration.mode == :test
18
- log "Params: #{env.fetch('steam.request').params.inspect}"
19
- end
20
-
17
+ debug_log "Params: #{env.fetch('steam.request').params.inspect}"
18
+
21
19
  app.call(env).tap do |response|
22
20
  done_in_ms = ((Time.now - now) * 10000).truncate / 10.0
23
21
  log "Completed #{code_to_human(response.first)} in #{done_in_ms}ms\n\n".green
@@ -13,10 +13,10 @@ module Locomotive::Steam
13
13
 
14
14
  if page = fetch_page
15
15
  if !page.not_found?
16
- log "Found page \"#{page.title}\" [#{page.fullpath}]"
16
+ debug_log "Found page \"#{page.title}\" [#{page.fullpath}]"
17
17
  else
18
18
  ActiveSupport::Notifications.instrument('steam.render.page_not_found', path: path, locale: locale, default_locale: default_locale)
19
- log "Page not found (#{path.inspect}), rendering the 404 page.".magenta
19
+ debug_log "Page not found (#{path.inspect}), rendering the 404 page.".magenta
20
20
  end
21
21
  end
22
22
 
@@ -47,7 +47,7 @@ module Locomotive::Steam
47
47
  regexp = Regexp.new(/^#{_route}$/i)
48
48
 
49
49
  if (matches = path.match(regexp))
50
- log "Route found! #{route} (#{handle})"
50
+ debug_log "Route found! #{route} (#{handle})"
51
51
 
52
52
  # we want the named route parameters in the request params object
53
53
  # because they will be needed in the liquid template.
@@ -63,7 +63,7 @@ module Locomotive::Steam
63
63
  def fetch_page_from_paths
64
64
  page_finder.match(path).tap do |pages|
65
65
  if pages.size > 1
66
- self.log "Found multiple pages: #{pages.map(&:title).join(', ')}"
66
+ self.debug_log "Found multiple pages: #{pages.map(&:title).join(', ')}"
67
67
  end
68
68
  end.first
69
69
  end
@@ -16,9 +16,15 @@ module Locomotive::Steam
16
16
  protected
17
17
 
18
18
  def set_path!(env)
19
+ site = env['steam.site']
19
20
  path = env['steam.path'].dup
20
21
 
21
- path.gsub!(/\.[a-zA-Z][a-zA-Z0-9]{2,}$/, '')
22
+ if site.allow_dots_in_slugs
23
+ path.gsub!(/\.(html|htm)$/, '')
24
+ else
25
+ path.gsub!(/\.[a-zA-Z][a-zA-Z0-9]{2,}$/, '')
26
+ end
27
+
22
28
  path.gsub!(/^\//, '')
23
29
  path.gsub!(/^[A-Z]:\//, '')
24
30
 
@@ -14,7 +14,7 @@ module Locomotive::Steam
14
14
  return if env['steam.private_access_disabled']
15
15
 
16
16
  if site.private_access
17
- log "Site with private access"
17
+ debug_log "Site with private access"
18
18
 
19
19
  if access_granted?
20
20
  store_password
@@ -28,7 +28,7 @@ module Locomotive::Steam
28
28
 
29
29
  def render_lock_screen
30
30
  if page = services.page_finder.by_handle('lock_screen', false)
31
- log "Found custom lock screen: #{page.title}"
31
+ debug_log "Found custom lock screen: #{page.title}"
32
32
  env['steam.page'] = page
33
33
  else
34
34
  render_response(lock_screen_html, 403)
@@ -26,7 +26,7 @@ module Locomotive::Steam
26
26
  env['steam.content_entry'] = page.content_entry = entry
27
27
 
28
28
  # log it
29
- log "Found content entry: #{entry._label}"
29
+ debug_log "Found content entry: #{entry._label}"
30
30
  else
31
31
  url = services.url_builder.url_for(page_not_found, locale)
32
32
  redirect_to url, 302
@@ -10,7 +10,7 @@ module Locomotive::Steam
10
10
  def _call
11
11
  timezone = site.try(:timezone)
12
12
 
13
- log "Timezone: #{timezone.name}"
13
+ debug_log "Timezone: #{timezone.name}"
14
14
 
15
15
  Time.use_zone(timezone) do
16
16
  self.next
@@ -65,8 +65,8 @@ module Locomotive::Steam
65
65
 
66
66
  alias :to_hash :translations
67
67
 
68
- def serialize(attributes)
69
- attributes[@name] = @translations
68
+ def serialize(attributes, custom_name = nil)
69
+ attributes[custom_name || @name] = @translations
70
70
  end
71
71
 
72
72
  def to_json
@@ -76,7 +76,8 @@ module Locomotive::Steam
76
76
 
77
77
  # localized fields
78
78
  @localized_attributes.each do |name|
79
- entity.send(name).serialize(attributes)
79
+ # hack: force the name for select type fields (content entries only)
80
+ entity.send(name).serialize(attributes, name)
80
81
  end
81
82
 
82
83
  # association name -> id (belongs_to) or ids (many_to_many)
@@ -73,6 +73,7 @@ module Locomotive
73
73
  end
74
74
  end
75
75
 
76
+ # Warning: do not work with localized and file fields
76
77
  def update_decorated_entry(decorated_entry, attributes)
77
78
  with_repository(decorated_entry.content_type) do |_repository|
78
79
  entry = decorated_entry.__getobj__
@@ -80,6 +81,17 @@ module Locomotive
80
81
 
81
82
  entry.change(_attributes)
82
83
 
84
+ # remove the proxy select fields because we don't need them at this point
85
+ # and MongoDB is going to complain when persisting it.
86
+ _repository.content_type.select_fields.each do |field|
87
+ entry.attributes.delete(field.name)
88
+ end
89
+
90
+ # remove any association field
91
+ _repository.content_type.association_fields.each do |field|
92
+ entry.attributes.delete(field.name)
93
+ end
94
+
83
95
  _repository.update(entry)
84
96
 
85
97
  logEntryOperation(decorated_entry.content_type.slug, decorated_entry)
@@ -3,6 +3,6 @@
3
3
  # 1.0.0.alpha < 1.0.0.alpha1 < 1.0.0.beta < 1.0.0.beta2 < 1.0.0.beta11 < 1.0.0.rc1 < 1.0.0
4
4
  module Locomotive
5
5
  module Steam
6
- VERSION = '1.6.0.beta1'
6
+ VERSION = '1.6.0'
7
7
  end
8
8
  end
@@ -48,6 +48,13 @@ module Locomotive
48
48
  def self.configure
49
49
  yield(configuration)
50
50
 
51
+ # configure the logger
52
+ Locomotive::Common.reset
53
+ Locomotive::Common.configure do |config|
54
+ config.notifier = Locomotive::Common::Logger.setup(configuration.log_file)
55
+ config.notifier.level = configuration.log_level
56
+ end
57
+
51
58
  require_relative 'steam/initializers'
52
59
  end
53
60
 
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.add_development_dependency 'mongo', '~> 2.13.1'
21
21
  spec.add_development_dependency 'origin', '~> 2.3.1'
22
22
 
23
- spec.add_dependency 'nokogiri', '~> 1.11.0'
23
+ spec.add_dependency 'nokogiri', '>= 1.11', '< 1.14'
24
24
  spec.add_dependency 'sanitize', '~> 5.2.1'
25
25
  spec.add_dependency 'morphine', '~> 0.1.1'
26
26
  spec.add_dependency 'httparty', '~> 0.16.0'
@@ -48,6 +48,8 @@ Gem::Specification.new do |spec|
48
48
  spec.add_dependency 'mime-types', '~> 3.3.0'
49
49
  spec.add_dependency 'duktape', '~> 2.0.1.1'
50
50
  spec.add_dependency 'pony', '~> 1.12'
51
+ spec.add_dependency 'parser', '~> 2.7'
52
+ spec.add_dependency 'unparser', '~> 0.4'
51
53
 
52
54
  spec.add_dependency 'locomotivecms_common', '~> 0.4.0'
53
55
 
@@ -22,6 +22,9 @@ order_by: manually
22
22
  # Activate public 'create' API (e.g for a contact form)
23
23
  # public_submission_enabled: false
24
24
 
25
+ # Enable Google Recaptcha to create new public entries
26
+ # recaptcha_required: true
27
+
25
28
  # Array of emails to be notified of new entries made with the public API
26
29
  # public_submission_accounts: ['john@example.com']
27
30
 
data/spec/spec_helper.rb CHANGED
@@ -45,7 +45,7 @@ RSpec.configure do |config|
45
45
  config.filter_run focused: true
46
46
  config.run_all_when_everything_filtered = true
47
47
 
48
- config.before(:all) { remove_logs; setup_common }
48
+ config.before(:all) { remove_logs; reset_logger }
49
49
  config.before { reset! }
50
50
  config.after { reset! }
51
51
  config.order = :random
@@ -19,7 +19,7 @@ module Spec
19
19
  FileUtils.rm_rf(File.expand_path('../../fixtures/default/log', __FILE__))
20
20
  end
21
21
 
22
- def setup_common(logger_output = nil)
22
+ def reset_logger(logger_output = nil)
23
23
  Locomotive::Common.reset
24
24
  Locomotive::Common.configure do |config|
25
25
  logger_output ||= File.join(default_fixture_site_path, 'log/steam.log')
@@ -30,9 +30,6 @@ module Spec
30
30
  def run_server
31
31
  require 'haml'
32
32
 
33
- output = ENV['STEAM_VERBOSE'] ? nil : File.join(default_fixture_site_path, 'log/steam.log')
34
- setup_common(output)
35
-
36
33
  Locomotive::Steam.configure do |config|
37
34
  config.mode = :test
38
35
  config.adapter = { name: :filesystem, path: default_fixture_site_path }
@@ -40,6 +37,7 @@ module Spec
40
37
  config.asset_path = File.expand_path(File.join(default_fixture_site_path, 'public'))
41
38
  config.serve_assets = true
42
39
  config.minify_assets = true
40
+ config.log_file = ENV['STEAM_VERBOSE'] ? nil : File.join(default_fixture_site_path, 'log/steam.log')
43
41
  end
44
42
 
45
43
  Locomotive::Common::Logger.info 'Server started...'
@@ -31,7 +31,7 @@ EOF
31
31
 
32
32
  let(:source) { '{% paginate projects by 2, window_size: 4 %}{% endpaginate %}' }
33
33
  let(:block) { subject.root.nodelist.first }
34
- it { expect(block.send(:window_size)).to eq 4 }
34
+ it { expect(block.send(:raw_attributes)[:window_size]).to eq 4 }
35
35
 
36
36
  end
37
37
 
@@ -63,6 +63,56 @@ describe Locomotive::Steam::Liquid::Tags::WithScope do
63
63
 
64
64
  end
65
65
 
66
+ describe 'decode advanced options' do
67
+ let(:options) { "" }
68
+ let(:source) { "{% with_scope key: #{options} %}{% assign conditions = with_scope %}{% endwith_scope %}" }
69
+ context "Array" do
70
+ context "of Integer" do
71
+ let(:options) { "[1, 2, 3]" }
72
+ it { expect(conditions['key']).to eq [1, 2, 3] }
73
+ end
74
+
75
+ context "of String" do
76
+ let(:options) { "['a', 'b', 'c']" }
77
+ it { expect(conditions['key']).to eq ['a', 'b', 'c'] }
78
+ end
79
+
80
+ context "With variable" do
81
+ let(:assigns) { {'a' => 1, 'c' => 3} }
82
+ let(:options) { "[a, 2, c, 'd']" }
83
+ it { expect(conditions['key']).to eq [1, 2, 3, 'd'] }
84
+ end
85
+ end
86
+
87
+ context "Hash" do
88
+ context "With key value" do
89
+ let(:options) { "{a: 1, b: 2, c: 3, d: 'foo'}" }
90
+ it { expect(conditions['key'].keys).to eq(%w(a b c d)) }
91
+ it { expect(conditions['key']['a']).to eq 1 }
92
+ it { expect(conditions['key']['b']).to eq 2 }
93
+ it { expect(conditions['key']['c']).to eq 3 }
94
+ it { expect(conditions['key']['d']).to eq 'foo' }
95
+ end
96
+
97
+ context "With key variable" do
98
+ let(:assigns) { {'a' => 1, 'c' => 3} }
99
+ let(:options) { "{a: a, b: 2, c: c, d: 'foo'}" }
100
+ it { expect(conditions['key'].keys).to eq(%w(a b c d)) }
101
+ it { expect(conditions['key']['a']).to eq 1 }
102
+ it { expect(conditions['key']['b']).to eq 2 }
103
+ it { expect(conditions['key']['c']).to eq 3 }
104
+ it { expect(conditions['key']['d']).to eq 'foo' }
105
+ end
106
+
107
+ context "With params" do
108
+ let(:assigns) { { 'params' => Locomotive::Steam::Liquid::Drops::Params.new({ foo: 'bar' }) } }
109
+ let(:options) { "{'a': params.foo}" }
110
+ it { expect(conditions['key'].keys).to eq(%w(a)) }
111
+ it { expect(conditions['key']['a']).to eq 'bar' }
112
+ end
113
+ end
114
+ end
115
+
66
116
  describe 'decode regexps' do
67
117
 
68
118
  let(:source) { "{% with_scope title: /Like this one|or this one/ %}{% assign conditions = with_scope %}{% endwith_scope %}" }
@@ -146,6 +196,15 @@ describe Locomotive::Steam::Liquid::Tags::WithScope do
146
196
 
147
197
  end
148
198
 
199
+ describe 'In a loop context, each scope should be evaluated correctly' do
200
+ let(:assigns) { {'list' => ['A', 'B', 'C']} }
201
+
202
+ let(:source) { "{% for key in list %}{% with_scope foo: key %}{% assign conditions = with_scope %}{% endwith_scope %}{{ conditions }}{% endfor %}" }
203
+
204
+ it { expect(output).to eq '{"foo"=>"A"}{"foo"=>"B"}{"foo"=>"C"}' }
205
+
206
+ end
207
+
149
208
  end
150
209
 
151
210
  end
@@ -55,11 +55,11 @@ describe Locomotive::Steam::Middlewares::Cache do
55
55
 
56
56
  let(:response) { nil }
57
57
 
58
- before { expect(cache).to receive(:read).with('9c535e0c37793cf8134e8b88b2517197').and_return(response) }
58
+ before { expect(cache).to receive(:read).with('c34181a7a079edc9de373067bffc28f0').and_return(response) }
59
59
 
60
60
  context 'the cache is empty' do
61
61
 
62
- before { expect(cache).to receive(:write).with('9c535e0c37793cf8134e8b88b2517197', Marshal.dump([200, {}, ["Hello world!"]])) }
62
+ before { expect(cache).to receive(:write).with('c34181a7a079edc9de373067bffc28f0', Marshal.dump([200, {}, ["Hello world!"]])) }
63
63
 
64
64
  it 'tells the CDN to cache the page and also cache it internally' do
65
65
  is_expected.to eq ['max-age=0, s-maxage=3600, public, must-revalidate', 'Accept-Language']
@@ -69,7 +69,7 @@ describe Locomotive::Steam::Middlewares::Cache do
69
69
 
70
70
  subject { send_request[:env]['steam.cache_etag'] }
71
71
 
72
- it { is_expected.to eq '9c535e0c37793cf8134e8b88b2517197' }
72
+ it { is_expected.to eq 'c34181a7a079edc9de373067bffc28f0' }
73
73
 
74
74
  end
75
75
 
@@ -104,7 +104,7 @@ describe Locomotive::Steam::Middlewares::Cache do
104
104
 
105
105
  context 'based on the ETag' do
106
106
 
107
- let(:etag) { '9c535e0c37793cf8134e8b88b2517197' }
107
+ let(:etag) { 'c34181a7a079edc9de373067bffc28f0' }
108
108
 
109
109
  it 'returns a 304 (Not modified) without no cache headers' do
110
110
  expect(subject.first).to eq 304
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ require_relative '../../../lib/locomotive/steam/middlewares/path'
4
+
5
+ describe Locomotive::Steam::Middlewares::Path do
6
+
7
+ let(:allow_dots_in_slugs) { false }
8
+ let(:site) { instance_double('Site', allow_dots_in_slugs: allow_dots_in_slugs) }
9
+ let(:routes) { {} }
10
+ let(:url) { 'http://models.example.com' }
11
+ let(:path) { 'hello-world' }
12
+ let(:app) { ->(env) { [200, env, 'app'] } }
13
+ let(:middleware) { described_class.new(app) }
14
+
15
+ subject do
16
+ env = env_for(url, 'steam.site' => site)
17
+ env['steam.path'] = path
18
+ env['steam.locale'] = 'en'
19
+ env['steam.request'] = Rack::Request.new(env)
20
+ code, env = middleware.call(env)
21
+ env['steam.path']
22
+ end
23
+
24
+ describe 'allow_dots_in_slugs is off' do
25
+ context 'html extension' do
26
+ let(:path) { 'foo.html' }
27
+ it { is_expected.to eq 'foo' }
28
+ end
29
+
30
+ context 'the path stores a version' do
31
+ let(:path) { 'foo-v1.0' }
32
+ it { is_expected.to eq 'foo-v1.0' }
33
+ end
34
+
35
+ context 'prefixed by 3 letters word' do
36
+ let(:path) { 'foo.bar' }
37
+ it { is_expected.to eq 'foo' }
38
+ end
39
+
40
+ context 'starting by a dot' do
41
+ let(:path) { '.well-known' }
42
+ it { is_expected.to eq '.well-known' }
43
+ end
44
+ end
45
+
46
+ describe 'allow_dots_in_slugs is on' do
47
+ let(:allow_dots_in_slugs) { true }
48
+
49
+ context 'html extension' do
50
+ let(:path) { 'foo.html' }
51
+ it { is_expected.to eq 'foo' }
52
+ end
53
+
54
+ context 'prefixed by a version' do
55
+ let(:path) { 'foo-v1.0' }
56
+ it { is_expected.to eq 'foo-v1.0' }
57
+ end
58
+
59
+ context 'prefixed by 3 letters word' do
60
+ let(:path) { 'foo.bar' }
61
+ it { is_expected.to eq 'foo.bar' }
62
+ end
63
+
64
+ context 'starting by a dot' do
65
+ let(:path) { '.well-known' }
66
+ it { is_expected.to eq '.well-known' }
67
+ end
68
+ end
69
+
70
+ end