locomotivecms_steam 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -7
  3. data/bin/steam.rb +1 -1
  4. data/lib/locomotive/steam/adapters/filesystem.rb +8 -1
  5. data/lib/locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb +27 -1
  6. data/lib/locomotive/steam/adapters/filesystem/sanitizers/site.rb +51 -0
  7. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb +8 -0
  8. data/lib/locomotive/steam/adapters/mongodb.rb +20 -1
  9. data/lib/locomotive/steam/adapters/mongodb/command.rb +8 -0
  10. data/lib/locomotive/steam/adapters/mongodb/query.rb +20 -1
  11. data/lib/locomotive/steam/entities/content_type.rb +1 -0
  12. data/lib/locomotive/steam/entities/content_type_field.rb +2 -1
  13. data/lib/locomotive/steam/entities/site.rb +3 -1
  14. data/lib/locomotive/steam/initializers/sprockets.rb +13 -3
  15. data/lib/locomotive/steam/liquid/drops/content_entry.rb +1 -1
  16. data/lib/locomotive/steam/liquid/drops/metafields.rb +97 -0
  17. data/lib/locomotive/steam/liquid/drops/site.rb +4 -0
  18. data/lib/locomotive/steam/liquid/filters/misc.rb +4 -0
  19. data/lib/locomotive/steam/liquid/tags/consume.rb +17 -6
  20. data/lib/locomotive/steam/liquid/tags/nav.rb +17 -11
  21. data/lib/locomotive/steam/middlewares/helpers.rb +1 -1
  22. data/lib/locomotive/steam/middlewares/page.rb +1 -0
  23. data/lib/locomotive/steam/middlewares/renderer.rb +8 -2
  24. data/lib/locomotive/steam/models/repository.rb +4 -0
  25. data/lib/locomotive/steam/repositories/content_type_field_repository.rb +4 -0
  26. data/lib/locomotive/steam/version.rb +1 -1
  27. data/locomotivecms_steam.gemspec +1 -1
  28. data/spec/fixtures/default/app/content_types/events.yml +1 -0
  29. data/spec/fixtures/default/app/views/pages/basic.liquid.haml +12 -0
  30. data/spec/fixtures/default/app/views/pages/tags/nav.liquid.haml +2 -0
  31. data/spec/fixtures/default/config/metafields_schema.yml +33 -0
  32. data/spec/fixtures/default/config/site.yml +13 -0
  33. data/spec/fixtures/default/data/events.yml +1 -2
  34. data/spec/integration/adapters/mongodb_spec.rb +49 -0
  35. data/spec/integration/repositories/content_entry_repository_spec.rb +26 -0
  36. data/spec/integration/server/metafields_spec.rb +26 -0
  37. data/spec/integration/server/nav_spec.rb +8 -0
  38. data/spec/unit/adapters/filesystem/sanitizers/site_spec.rb +59 -0
  39. data/spec/unit/adapters/filesystem/yaml_loaders/site_spec.rb +12 -2
  40. data/spec/unit/adapters/filesystem_adapter_spec.rb +18 -0
  41. data/spec/unit/adapters/mongodb/query_spec.rb +25 -1
  42. data/spec/unit/entities/content_type_spec.rb +10 -0
  43. data/spec/unit/initializers/sprockets_spec.rb +36 -0
  44. data/spec/unit/liquid/drops/content_entry_spec.rb +3 -1
  45. data/spec/unit/liquid/drops/metafields_spec.rb +81 -0
  46. data/spec/unit/liquid/filters/misc_spec.rb +13 -0
  47. data/spec/unit/liquid/tags/consume_spec.rb +7 -0
  48. data/spec/unit/liquid/tags/nav_spec.rb +9 -1
  49. data/spec/unit/liquid/tags/path_to_spec.rb +1 -1
  50. data/spec/unit/middlewares/helpers_spec.rb +32 -0
  51. data/spec/unit/middlewares/renderer_spec.rb +17 -2
  52. data/spec/unit/repositories/content_entry_repository_spec.rb +11 -11
  53. data/spec/unit/repositories/content_type_field_repository_spec.rb +10 -0
  54. metadata +18 -4
@@ -14,6 +14,10 @@ module Locomotive
14
14
  liquify(*self.scoped_pages)
15
15
  end
16
16
 
17
+ def metafields
18
+ @metafields ||= Metafields.new(@_source)
19
+ end
20
+
17
21
  protected
18
22
 
19
23
  def repository
@@ -14,6 +14,10 @@ module Locomotive
14
14
  array.at(position) if array.respond_to?(:at)
15
15
  end
16
16
 
17
+ def shuffle(array)
18
+ array.to_a.shuffle
19
+ end
20
+
17
21
  def default(input, value)
18
22
  input.blank? ? value : input
19
23
  end
@@ -3,7 +3,7 @@ module Locomotive
3
3
  module Liquid
4
4
  module Tags
5
5
 
6
- # Consume web services as easy as pie directly in liquid !
6
+ # Consume web services as easy as pie directly in liquid!
7
7
  #
8
8
  # Usage:
9
9
  #
@@ -33,11 +33,16 @@ module Locomotive
33
33
  def render(context)
34
34
  self.set_api_options(context)
35
35
 
36
- if instance_variable_defined? :@variable_name
36
+ if instance_variable_defined?(:@variable_name)
37
37
  @url = context[@variable_name]
38
38
  end
39
39
 
40
- render_all_and_cache_it(context)
40
+ if @url.blank?
41
+ Locomotive::Common::Logger.error "A consume tag can't call an empty URL."
42
+ ''
43
+ else
44
+ render_all_and_cache_it(context)
45
+ end
41
46
  end
42
47
 
43
48
  protected
@@ -52,11 +57,11 @@ module Locomotive
52
57
 
53
58
  def set_api_options(context)
54
59
  @api_options = interpolate_options(@default_api_options, context)
55
- @expires_in = @api_options.delete(:expires_in) || 0
60
+ @expires_in = @api_options.delete(:expires_in).try(:to_i)
56
61
  end
57
62
 
58
63
  def render_all_and_cache_it(context)
59
- cache_service(context).fetch(page_fragment_cache_key, expires_in: @expires_in, force: @expires_in == 0) do
64
+ cache_service(context).fetch(page_fragment_cache_key, cache_options) do
60
65
  self.render_all_without_cache(context)
61
66
  end
62
67
  end
@@ -64,6 +69,8 @@ module Locomotive
64
69
  def render_all_without_cache(context)
65
70
  context.stack do
66
71
  begin
72
+ Locomotive::Common::Logger.info "[consume] #{@url.inspect} / #{@api_options.inspect}"
73
+
67
74
  context.scopes.last[@name] = service(context).consume(@url, @api_options)
68
75
  rescue Timeout::Error
69
76
  context.scopes.last[@name] = last_response(context)
@@ -81,12 +88,16 @@ module Locomotive
81
88
  context.registers[:services].cache
82
89
  end
83
90
 
91
+ def cache_options
92
+ @expires_in.blank? ? { force: true } : { expires_in: @expires_in }
93
+ end
94
+
84
95
  def last_response(context)
85
96
  cache_service(context).read(page_fragment_cache_key)
86
97
  end
87
98
 
88
99
  def page_fragment_cache_key
89
- Digest::SHA1.hexdigest(@name + @url)
100
+ "Steam-consume-#{Digest::SHA1.hexdigest(@name + @url)}"
90
101
  end
91
102
 
92
103
  end
@@ -35,7 +35,7 @@ module Locomotive
35
35
 
36
36
  # get all the children of a source: site (index page), parent or page.
37
37
  pages = children_of(fetch_starting_page)
38
- output = self.build_entries_output(pages)
38
+ output = self.build_entries_output(pages, context)
39
39
 
40
40
  if self.no_wrapper?
41
41
  output
@@ -54,7 +54,7 @@ module Locomotive
54
54
  #
55
55
  # @return [ String ] The final HTML output
56
56
  #
57
- def build_entries_output(pages, depth = 1)
57
+ def build_entries_output(pages, depth = 1, context)
58
58
  output = []
59
59
 
60
60
  pages.each_with_index do |page, index|
@@ -62,7 +62,7 @@ module Locomotive
62
62
  css << 'first' if index == 0
63
63
  css << 'last' if index == pages.size - 1
64
64
 
65
- output << self.render_entry_link(page, css.join(' '), depth)
65
+ output << self.render_entry_link(page, css.join(' '), depth, context)
66
66
  end
67
67
 
68
68
  output.join("\n")
@@ -133,9 +133,9 @@ module Locomotive
133
133
  #
134
134
  # @return [ String ] The label in HTML
135
135
  #
136
- def entry_label(page)
136
+ def entry_label(page, context)
137
137
  icon = @_options[:icon] ? '<span></span>' : ''
138
- title = @_options[:liquid_render] ? @_options[:liquid_render].render('page' => page) : page.title
138
+ title = @_options[:liquid_render] ? @_options[:liquid_render].render({ 'page' => page }, registers: context.registers) : page.title
139
139
 
140
140
  if icon.blank?
141
141
  title
@@ -178,10 +178,10 @@ module Locomotive
178
178
  #
179
179
  # @return [ String ] The HTML output
180
180
  #
181
- def render_entry_link(page, css, depth)
181
+ def render_entry_link(page, css, depth, context)
182
182
  page = decorate_page(page)
183
183
  url = self.entry_url(page)
184
- label = self.entry_label(page)
184
+ label = self.entry_label(page, context)
185
185
  css = self.entry_css(page, css)
186
186
  options = ''
187
187
 
@@ -193,7 +193,7 @@ module Locomotive
193
193
  end
194
194
 
195
195
  self.render_tag(:li, id: "#{page.slug.to_s.dasherize}-link", css: css) do
196
- children_output = depth.succ <= @_options[:depth].to_i ? self.render_entry_children(page, depth.succ) : ''
196
+ children_output = depth.succ <= @_options[:depth].to_i ? self.render_entry_children(page, depth.succ, context) : ''
197
197
  %{<a href="#{url}"#{options}>#{label}</a>} + children_output
198
198
  end
199
199
  end
@@ -205,13 +205,13 @@ module Locomotive
205
205
  #
206
206
  # @return [ String ] The HTML code
207
207
  #
208
- def render_entry_children(page, depth)
208
+ def render_entry_children(page, depth, context)
209
209
  entries = children_of(page)
210
210
  css = self.bootstrap? ? 'dropdown-menu' : ''
211
211
 
212
212
  unless entries.empty?
213
213
  self.render_tag(:ul, id: "#{@_options[:id]}-#{page.slug.to_s.dasherize}", css: css) do
214
- self.build_entries_output(entries, depth)
214
+ self.build_entries_output(entries, depth, context)
215
215
  end
216
216
  else
217
217
  ''
@@ -254,7 +254,13 @@ module Locomotive
254
254
  source = if template_name.include?('{{')
255
255
  template_name
256
256
  else
257
- services.snippet_finder.find(template_name).try(:source)
257
+ snippet = services.snippet_finder.find(template_name)
258
+ if snippet
259
+ snippet.liquid_source
260
+ else
261
+ Locomotive::Common::Logger.warn "[Liquid][Nav] unable to find the #{template_name} snippet"
262
+ nil
263
+ end
258
264
  end
259
265
 
260
266
  source ? ::Liquid::Template.parse(source) : nil
@@ -18,7 +18,7 @@ module Locomotive::Steam
18
18
  end
19
19
 
20
20
  def redirect_to(location, type = 301)
21
- _location = mounted_on && (location =~ Locomotive::Steam::IsHTTP).nil? ? "#{mounted_on}#{location}" : location
21
+ _location = mounted_on && !location.starts_with?(mounted_on) && (location =~ Locomotive::Steam::IsHTTP).nil? ? "#{mounted_on}#{location}" : location
22
22
 
23
23
  self.log "Redirected to #{_location}".blue
24
24
 
@@ -15,6 +15,7 @@ module Locomotive::Steam
15
15
  if !page.not_found?
16
16
  log "Found page \"#{page.title}\" [#{page.fullpath}]"
17
17
  else
18
+ ActiveSupport::Notifications.instrument('steam.render.page_not_found', path: path, locale: locale, default_locale: default_locale)
18
19
  log "Page not found, rendering the 404 page.".magenta
19
20
  end
20
21
  end
@@ -25,8 +25,14 @@ module Locomotive::Steam
25
25
  end
26
26
 
27
27
  def render_missing_404
28
- log "[Warning] Your 404 page is missing. Please create it.".red
29
- render_response('Missing 404 page', 404)
28
+ message = (if locale != default_locale
29
+ "Your 404 page is missing in the #{locale} locale."
30
+ else
31
+ "Your 404 page is missing."
32
+ end) + " Please create it."
33
+
34
+ log "[Warning] #{message}".red
35
+ render_response(message, 404)
30
36
  end
31
37
 
32
38
  def parse_and_render_liquid
@@ -32,6 +32,10 @@ module Locomotive::Steam
32
32
  adapter.create(mapper, scope, entity)
33
33
  end
34
34
 
35
+ def inc(entity, attribute, amount = 1)
36
+ adapter.inc(mapper, entity, attribute, amount)
37
+ end
38
+
35
39
  def delete(entity)
36
40
  adapter.delete(mapper, scope, entity)
37
41
  end
@@ -53,6 +53,10 @@ module Locomotive
53
53
  query { where(localized: true) }.all.map(&:name)
54
54
  end
55
55
 
56
+ def default
57
+ query { where(k(:default, :neq) => nil, k(:type, :in) => [:string, :text, :color, :select, :boolean, :email, :integer, :float]) }.all
58
+ end
59
+
56
60
  def select_options(name)
57
61
  if field = first { where(name: name, type: :select) }
58
62
  field.select_options.all
@@ -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.0.0'
6
+ VERSION = '1.0.1'
7
7
  end
8
8
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency 'mongo', '~> 2.2.1'
22
22
  spec.add_development_dependency 'origin', '~> 2.1.1'
23
23
 
24
- spec.add_dependency 'nokogiri', '~> 1.6.7.1'
24
+ spec.add_dependency 'nokogiri', '~> 1.6.7.2'
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'
@@ -12,6 +12,7 @@ fields:
12
12
  - city:
13
13
  type: string
14
14
  label: City of the event
15
+ default: Chicago
15
16
  - state:
16
17
  type: string
17
18
  label: State of the event
@@ -12,3 +12,15 @@ position: 6
12
12
  %body
13
13
  %p
14
14
  This is a basic page
15
+
16
+ %ul
17
+ %li Color scheme={{ site.metafields.theme.color_scheme }}
18
+ %li Facebook ID={{ site.metafields.social.facebook_id }}
19
+ %li Google ID={{ site.metafields.social.google_id }}
20
+ %li API URL={{ site.metafields.github.api_url }}
21
+ %li Expires In={{ site.metafields.github.expires_in }}
22
+
23
+ %ul
24
+ {% for property in site.metafields.social %}
25
+ %li.property {{ property.label }}({{ property.name }})={{ property.value }}
26
+ {% endfor %}
@@ -4,3 +4,5 @@ listed: false
4
4
  published: true
5
5
  ---
6
6
  {% nav site %}
7
+
8
+ {% nav site, snippet: "-{{ page.title }}-" %}
@@ -0,0 +1,33 @@
1
+ theme:
2
+ fields:
3
+ color_scheme:
4
+ localized: true
5
+
6
+ social:
7
+ label:
8
+ fr: Social (FR)
9
+ position: 1
10
+ fields:
11
+ - facebook_id
12
+ - google_id
13
+
14
+ github:
15
+ position: 0
16
+ fields:
17
+ api_url:
18
+ label:
19
+ en: 'API Url'
20
+ fr: "Url de l'API"
21
+ type: string
22
+ hint: 'API endpoint'
23
+ expires_in:
24
+ label:
25
+ en: 'Expires in'
26
+ fr: 'Expire dans'
27
+ hint:
28
+ en: 'Cache - In milliseconds'
29
+ fr: 'Cache - En millisecondes'
30
+ type: integer
31
+ min: 0
32
+ max: 3600
33
+
@@ -19,3 +19,16 @@ meta_keywords:
19
19
  meta_description: some meta description
20
20
 
21
21
  robots_txt: "User-agent: *\nDisallow:"
22
+
23
+ metafields:
24
+ theme:
25
+ color_scheme:
26
+ en: 'white'
27
+ fr: 'blue'
28
+ nb: 'red'
29
+ social:
30
+ facebook_id: 'FB42'
31
+ google_id: 'G42'
32
+ github:
33
+ api_url: https://api.github.com/repos/vmg/redcarpet/issues?state=closed
34
+ expires_in: 42
@@ -45,9 +45,8 @@
45
45
  state: Missouri
46
46
  - Ballydoyle's:
47
47
  date: 2011/06/05
48
- city: Aurora
49
48
  state: Illinois
50
49
  - The Belmont:
51
50
  date: 2011/06/04
52
51
  city: Hamtramk
53
- state: Michigan
52
+ state: Michigan
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ require_relative '../../../lib/locomotive/steam/adapters/mongodb.rb'
4
+
5
+ describe Locomotive::Steam::MongoDBAdapter do
6
+
7
+ let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017'], min_pool_size: 2, max_pool_size: 5) }
8
+
9
+ before(:all) do
10
+ described_class.disconnect_session
11
+ @before_connections = current_connections
12
+ end
13
+
14
+ describe '#session' do
15
+
16
+ subject { adapter.send(:session) }
17
+
18
+ it { is_expected.not_to eq nil }
19
+
20
+ it "don't create more Mongo sessions than the max pool" do
21
+ 10.times { subject['locomotive_sites'].find.count }
22
+ _after = current_connections
23
+ expect(_after).to be >= (@before_connections + 2) # min_pool_size
24
+ expect(_after).to be <= (@before_connections + 5) # max_pool_size
25
+ end
26
+
27
+ end
28
+
29
+ describe '.disconnect_session' do
30
+
31
+ let(:connection) { adapter.send(:session) }
32
+
33
+ subject { described_class.disconnect_session }
34
+
35
+ it { is_expected.to eq nil }
36
+
37
+ it 'closes clients' do
38
+ 10.times { connection['locomotive_sites'].find.count }
39
+ subject
40
+ expect(current_connections).to eq @before_connections
41
+ end
42
+
43
+ end
44
+
45
+ def current_connections
46
+ `mongo --eval "db.serverStatus().connections.current"`.split("\n").last.to_i
47
+ end
48
+
49
+ end
@@ -61,6 +61,16 @@ describe Locomotive::Steam::ContentEntryRepository do
61
61
  it { expect(subject.map { |h| h[:entries].size }).to eq([2, 1, 0]) }
62
62
  end
63
63
 
64
+ describe '#order_by' do
65
+ let(:order_by) { 'name' }
66
+ subject { repository.all(order_by: order_by) }
67
+ it { expect(subject.map { |h| h[:name] }).to eq(['Alice in Chains', 'Pearl Jam', 'The who']) }
68
+ context 'a field and a direction' do
69
+ let(:order_by) { 'name.desc, leader asc' }
70
+ it { expect(subject.map { |h| h[:name] }).to eq(['The who', 'Pearl Jam', 'Alice in Chains']) }
71
+ end
72
+ end
73
+
64
74
  describe '#create' do
65
75
 
66
76
  let(:type) { type_repository.by_slug('songs') }
@@ -76,6 +86,22 @@ describe Locomotive::Steam::ContentEntryRepository do
76
86
 
77
87
  end
78
88
 
89
+ describe '#inc' do
90
+
91
+ let(:type) { type_repository.by_slug('songs') }
92
+ let(:attributes) { { title: 'Jeremy', band: 'pearl-jam', short_description: '"Jeremy" is a song by the American rock band Pearl Jam', views: 41 } }
93
+ let(:entry) { repository.with(type).build(attributes) }
94
+
95
+ before { repository.create(entry) }
96
+
97
+ subject { repository.inc(entry, :views) }
98
+
99
+ it { expect(subject.views).to eq 42 }
100
+
101
+ after { repository.delete(entry) }
102
+
103
+ end
104
+
79
105
  end
80
106
 
81
107
  context 'MongoDB' do