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.
- checksums.yaml +4 -4
- data/Gemfile.lock +7 -7
- data/bin/steam.rb +1 -1
- data/lib/locomotive/steam/adapters/filesystem.rb +8 -1
- data/lib/locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb +27 -1
- data/lib/locomotive/steam/adapters/filesystem/sanitizers/site.rb +51 -0
- data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb +8 -0
- data/lib/locomotive/steam/adapters/mongodb.rb +20 -1
- data/lib/locomotive/steam/adapters/mongodb/command.rb +8 -0
- data/lib/locomotive/steam/adapters/mongodb/query.rb +20 -1
- data/lib/locomotive/steam/entities/content_type.rb +1 -0
- data/lib/locomotive/steam/entities/content_type_field.rb +2 -1
- data/lib/locomotive/steam/entities/site.rb +3 -1
- data/lib/locomotive/steam/initializers/sprockets.rb +13 -3
- data/lib/locomotive/steam/liquid/drops/content_entry.rb +1 -1
- data/lib/locomotive/steam/liquid/drops/metafields.rb +97 -0
- data/lib/locomotive/steam/liquid/drops/site.rb +4 -0
- data/lib/locomotive/steam/liquid/filters/misc.rb +4 -0
- data/lib/locomotive/steam/liquid/tags/consume.rb +17 -6
- data/lib/locomotive/steam/liquid/tags/nav.rb +17 -11
- data/lib/locomotive/steam/middlewares/helpers.rb +1 -1
- data/lib/locomotive/steam/middlewares/page.rb +1 -0
- data/lib/locomotive/steam/middlewares/renderer.rb +8 -2
- data/lib/locomotive/steam/models/repository.rb +4 -0
- data/lib/locomotive/steam/repositories/content_type_field_repository.rb +4 -0
- data/lib/locomotive/steam/version.rb +1 -1
- data/locomotivecms_steam.gemspec +1 -1
- data/spec/fixtures/default/app/content_types/events.yml +1 -0
- data/spec/fixtures/default/app/views/pages/basic.liquid.haml +12 -0
- data/spec/fixtures/default/app/views/pages/tags/nav.liquid.haml +2 -0
- data/spec/fixtures/default/config/metafields_schema.yml +33 -0
- data/spec/fixtures/default/config/site.yml +13 -0
- data/spec/fixtures/default/data/events.yml +1 -2
- data/spec/integration/adapters/mongodb_spec.rb +49 -0
- data/spec/integration/repositories/content_entry_repository_spec.rb +26 -0
- data/spec/integration/server/metafields_spec.rb +26 -0
- data/spec/integration/server/nav_spec.rb +8 -0
- data/spec/unit/adapters/filesystem/sanitizers/site_spec.rb +59 -0
- data/spec/unit/adapters/filesystem/yaml_loaders/site_spec.rb +12 -2
- data/spec/unit/adapters/filesystem_adapter_spec.rb +18 -0
- data/spec/unit/adapters/mongodb/query_spec.rb +25 -1
- data/spec/unit/entities/content_type_spec.rb +10 -0
- data/spec/unit/initializers/sprockets_spec.rb +36 -0
- data/spec/unit/liquid/drops/content_entry_spec.rb +3 -1
- data/spec/unit/liquid/drops/metafields_spec.rb +81 -0
- data/spec/unit/liquid/filters/misc_spec.rb +13 -0
- data/spec/unit/liquid/tags/consume_spec.rb +7 -0
- data/spec/unit/liquid/tags/nav_spec.rb +9 -1
- data/spec/unit/liquid/tags/path_to_spec.rb +1 -1
- data/spec/unit/middlewares/helpers_spec.rb +32 -0
- data/spec/unit/middlewares/renderer_spec.rb +17 -2
- data/spec/unit/repositories/content_entry_repository_spec.rb +11 -11
- data/spec/unit/repositories/content_type_field_repository_spec.rb +10 -0
- metadata +18 -4
@@ -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?
|
36
|
+
if instance_variable_defined?(:@variable_name)
|
37
37
|
@url = context[@variable_name]
|
38
38
|
end
|
39
39
|
|
40
|
-
|
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)
|
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,
|
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)
|
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
|
-
|
29
|
-
|
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
|
@@ -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
|
data/locomotivecms_steam.gemspec
CHANGED
@@ -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.
|
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,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 %}
|
@@ -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
|
@@ -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
|