locomotivecms_steam 0.1.1 → 0.1.2.pre.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +5 -0
- data/Gemfile +10 -2
- data/Gemfile.lock +37 -49
- data/Rakefile +5 -10
- data/example/server.rb +10 -6
- data/lib/locomotive/steam.rb +46 -0
- data/lib/locomotive/steam/configuration.rb +13 -0
- data/lib/locomotive/steam/decorators.rb +1 -0
- data/lib/locomotive/steam/decorators/page_decorator.rb +50 -0
- data/lib/locomotive/steam/entities/content_type.rb +11 -0
- data/lib/locomotive/steam/entities/page.rb +136 -0
- data/lib/locomotive/steam/entities/site.rb +30 -0
- data/lib/locomotive/steam/initializers/dragonfly.rb +3 -4
- data/lib/locomotive/steam/liquid.rb +1 -12
- data/lib/locomotive/steam/liquid/drops/base.rb +1 -1
- data/lib/locomotive/steam/liquid/drops/content_entry.rb +3 -2
- data/lib/locomotive/steam/liquid/drops/content_types.rb +4 -2
- data/lib/locomotive/steam/liquid/drops/page.rb +4 -3
- data/lib/locomotive/steam/liquid/drops/site.rb +3 -2
- data/lib/locomotive/steam/liquid/patches.rb +4 -8
- data/lib/locomotive/steam/liquid/tags/nav.rb +19 -17
- data/lib/locomotive/steam/loaders/yml/pages_loader.rb +193 -0
- data/lib/locomotive/steam/loaders/yml/site_loader.rb +49 -0
- data/lib/locomotive/steam/loaders/yml/utils/localized_tree.rb +33 -0
- data/lib/locomotive/steam/loaders/yml/utils/yaml_front_matters_template.rb +66 -0
- data/lib/locomotive/steam/loaders/yml_loader.rb +33 -0
- data/lib/locomotive/steam/mapper.rb +86 -0
- data/lib/locomotive/steam/middlewares/base.rb +12 -10
- data/lib/locomotive/steam/middlewares/locale.rb +3 -4
- data/lib/locomotive/steam/middlewares/page.rb +18 -18
- data/lib/locomotive/steam/middlewares/renderer.rb +41 -15
- data/lib/locomotive/steam/middlewares/stack.rb +1 -1
- data/lib/locomotive/steam/monkey_patches.rb +1 -2
- data/lib/locomotive/steam/monkey_patches/haml.rb +1 -1
- data/lib/locomotive/steam/repositories/content_types_repository.rb +14 -0
- data/lib/locomotive/steam/repositories/pages_repository.rb +23 -0
- data/lib/locomotive/steam/repositories/sites_repository.rb +16 -0
- data/lib/locomotive/steam/server.rb +14 -11
- data/lib/locomotive/steam/services/external_api.rb +2 -1
- data/lib/locomotive/steam/services/markdown.rb +3 -12
- data/lib/locomotive/steam/standalone_server.rb +2 -2
- data/lib/locomotive/steam/version.rb +4 -1
- data/locomotivecms_steam.gemspec +11 -5
- data/spec/fixtures/default/app/views/pages/basic.liquid.haml +13 -0
- data/spec/fixtures/default/config/site.yml +2 -2
- data/spec/integration/server/basic_spec.rb +22 -17
- data/spec/integration/server/contact_form_spec.rb +1 -1
- data/spec/integration/server/liquid_spec.rb +2 -2
- data/spec/integration/server/with_scope_spec.rb +2 -2
- data/spec/spec_helper.rb +15 -4
- data/spec/support/helpers.rb +26 -8
- data/spec/unit/decorators/page_decorator_spec.rb +55 -0
- data/spec/unit/entities/page_spec.rb +50 -0
- data/spec/unit/entities/site_spec.rb +12 -0
- data/spec/unit/liquid/tags/nav_spec.rb +159 -0
- data/spec/unit/loaders/pages_loader_spec.rb +42 -0
- data/spec/unit/loaders/site_loader_spec.rb +21 -0
- data/spec/unit/loaders/utils/localized_tree_spec.rb +33 -0
- data/spec/unit/loaders/utils/yaml_front_matters_template_spec.rb +39 -0
- data/spec/unit/middlewares/base_spec.rb +20 -0
- data/spec/unit/middlewares/page_spec.rb +51 -0
- data/spec/unit/repositories/pages_spec.rb +11 -0
- metadata +128 -23
- data/bin/publish +0 -28
- data/lib/locomotive/steam/misc.rb +0 -10
- data/lib/locomotive/steam/monkey_patches/mounter.rb +0 -54
- data/lib/steam.rb +0 -3
@@ -0,0 +1,49 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Loader
|
4
|
+
module Yml
|
5
|
+
class SiteLoader
|
6
|
+
def initialize(path, mapper)
|
7
|
+
@root_path = path
|
8
|
+
@path = File.join(@root_path, 'config', 'site.yml')
|
9
|
+
@mapper = mapper
|
10
|
+
end
|
11
|
+
|
12
|
+
def load!
|
13
|
+
entity_class = @mapper.collection(:sites).entity
|
14
|
+
repository = @mapper.collection(:sites).repository
|
15
|
+
all.each do |site_hash|
|
16
|
+
site = entity_class.new(site_hash)
|
17
|
+
repository.create site
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def all
|
24
|
+
attributes = load_attributes
|
25
|
+
(attributes['domains'] ||= []) << '0.0.0.0'
|
26
|
+
%w{seo_title meta_keywords meta_description}.each do |field|
|
27
|
+
attributes[field] = to_locale(attributes[field], attributes['locales'].first)
|
28
|
+
end
|
29
|
+
[attributes]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_locale(field, default)
|
33
|
+
return field if field.respond_to?(:[]) && field[default]
|
34
|
+
{ "#{default}" => field }
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_attributes
|
38
|
+
if File.exists?(@path)
|
39
|
+
file = File.read(@path).force_encoding('utf-8')
|
40
|
+
YAML::load(file)
|
41
|
+
else
|
42
|
+
raise "#{@path} was not found"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Utils
|
4
|
+
class LocalizedTree
|
5
|
+
|
6
|
+
def initialize(entries, extensions)
|
7
|
+
@entries = entries
|
8
|
+
@extensions = extensions
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_hash
|
12
|
+
group_by(locale_regexp)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def group_by(regexp)
|
19
|
+
@entries.each_with_object({}) do |entry, hsh|
|
20
|
+
file, key, subkey, *_ = regexp.match(entry).to_a
|
21
|
+
next unless file
|
22
|
+
(hsh[key] ||= {})[subkey.try(:to_sym) || :default] = file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def locale_regexp
|
27
|
+
/\A(.+?)(?:\.(.{2})){0,1}\.(?:(#{@extensions.join('|')})\.*)+\Z/
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
# YAML Front-matters for HAML/Liquid templates
|
6
|
+
class YAMLFrontMattersTemplate
|
7
|
+
|
8
|
+
attr_reader :filepath
|
9
|
+
|
10
|
+
def initialize(filepath)
|
11
|
+
@filepath = filepath
|
12
|
+
@line_offset = 0
|
13
|
+
@parsed = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def attributes
|
17
|
+
self.fetch_attributes_and_raw_source
|
18
|
+
@attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
def raw_source
|
22
|
+
self.fetch_attributes_and_raw_source
|
23
|
+
@raw_source
|
24
|
+
end
|
25
|
+
|
26
|
+
def line_offset
|
27
|
+
self.fetch_attributes_and_raw_source
|
28
|
+
@line_offset
|
29
|
+
end
|
30
|
+
|
31
|
+
def source
|
32
|
+
self.fetch_attributes_and_raw_source
|
33
|
+
return @source if @source
|
34
|
+
|
35
|
+
@source = if self.filepath.ends_with?('.haml')
|
36
|
+
Haml::Engine.new(self.raw_source).render
|
37
|
+
else
|
38
|
+
self.raw_source
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def data
|
43
|
+
@data ||= File.read(filepath)
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
def parsed?
|
48
|
+
@parsed
|
49
|
+
end
|
50
|
+
def fetch_attributes_and_raw_source
|
51
|
+
return if @parsed
|
52
|
+
if data =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)(.*)/m
|
53
|
+
@line_offset = $1.count("\n") + 1
|
54
|
+
@attributes = YAML.load($1)
|
55
|
+
@raw_source = $3
|
56
|
+
else
|
57
|
+
@attributes = {}
|
58
|
+
@raw_source = data
|
59
|
+
end
|
60
|
+
@raw_source.force_encoding('utf-8')
|
61
|
+
@parsed = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'yml/site_loader'
|
2
|
+
require_relative 'yml/pages_loader'
|
3
|
+
require_relative 'yml/utils/yaml_front_matters_template'
|
4
|
+
require_relative 'yml/utils/localized_tree'
|
5
|
+
|
6
|
+
module Locomotive
|
7
|
+
module Steam
|
8
|
+
module Loader
|
9
|
+
class YmlLoader
|
10
|
+
|
11
|
+
MODELS = %W[site]
|
12
|
+
|
13
|
+
def initialize path, mapper
|
14
|
+
@root_path, @mapper = path, mapper
|
15
|
+
end
|
16
|
+
|
17
|
+
def load!
|
18
|
+
load_site!
|
19
|
+
load_pages!
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_site!
|
23
|
+
Locomotive::Steam::Loader::Yml::SiteLoader.new(@root_path, @mapper).load!
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_pages!
|
27
|
+
Locomotive::Steam::Loader::Yml::PagesLoader.new(@root_path, @mapper).load!
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + '/entities/*.rb'].each { |file| require file }
|
2
|
+
Dir[File.dirname(__FILE__) + '/repositories/*.rb'].each { |file| require file }
|
3
|
+
|
4
|
+
collection :sites do
|
5
|
+
entity Locomotive::Steam::Entities::Site
|
6
|
+
repository Locomotive::Steam::Repositories::SitesRepository
|
7
|
+
|
8
|
+
attribute :name
|
9
|
+
attribute :locales
|
10
|
+
attribute :subdomain
|
11
|
+
attribute :domains
|
12
|
+
attribute :seo_title, localized: true
|
13
|
+
attribute :meta_keywords, localized: true
|
14
|
+
attribute :meta_description, localized: true
|
15
|
+
attribute :robots_txt
|
16
|
+
attribute :timezone
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
collection :pages do
|
22
|
+
entity Locomotive::Steam::Entities::Page
|
23
|
+
repository Locomotive::Steam::Repositories::PagesRepository
|
24
|
+
|
25
|
+
attribute :site, association: {type: :belongs_to, key: :site_id, name: :sites}
|
26
|
+
attribute :content_type, association: {type: :belongs_to, key: :content_type_id, name: :content_types}
|
27
|
+
attribute :parent, association: {type: :belongs_to, key: :parent_id, name: :pages}
|
28
|
+
attribute :children, association: {type: :has_many, key: :parent_id, name: :pages}
|
29
|
+
attribute :title, localized: true
|
30
|
+
attribute :slug, localized: true
|
31
|
+
attribute :fullpath, localized: true
|
32
|
+
attribute :redirect_url, localized: true
|
33
|
+
attribute :redirect_type, default: 301
|
34
|
+
attribute :template, localized: true
|
35
|
+
attribute :handle
|
36
|
+
attribute :listed, default: false
|
37
|
+
attribute :searchable
|
38
|
+
attribute :templatized, default: false
|
39
|
+
attribute :content_type
|
40
|
+
attribute :published, default: true
|
41
|
+
attribute :cache_strategy
|
42
|
+
attribute :response_type
|
43
|
+
attribute :position
|
44
|
+
|
45
|
+
attribute :seo_title, localized: true
|
46
|
+
attribute :meta_keywords, localized: true
|
47
|
+
attribute :meta_description, localized: true
|
48
|
+
|
49
|
+
attribute :editable_elements, type: :array, class_name: 'Locomotive::Mounter::Models::EditableElement'
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
collection :content_types do
|
54
|
+
entity Locomotive::Steam::Entities::ContentType
|
55
|
+
repository Locomotive::Steam::Repositories::ContentTypesRepository
|
56
|
+
attribute :slug
|
57
|
+
attribute :site, association: {type: :belongs_to, key: :site_id, name: :sites}
|
58
|
+
end
|
59
|
+
|
60
|
+
collection :content_entries do
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
collection :content_fields do
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
collection :content_select_options do
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
collection :editable_elements do
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
collection :snippets do
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
collection :theme_assets do
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
collection :translations do
|
85
|
+
|
86
|
+
end
|
@@ -5,33 +5,35 @@ module Locomotive::Steam
|
|
5
5
|
|
6
6
|
attr_accessor :app, :request, :path
|
7
7
|
attr_accessor :liquid_assigns, :services
|
8
|
-
attr_accessor :
|
8
|
+
attr_accessor :site, :page, :content_entry, :locale
|
9
9
|
|
10
10
|
def initialize(app = nil)
|
11
11
|
@app = app
|
12
12
|
end
|
13
13
|
|
14
14
|
def call(env)
|
15
|
-
|
15
|
+
if Locomotive::Steam.mode == :test
|
16
|
+
_call(env)
|
17
|
+
else
|
18
|
+
dup._call(env) # thread-safe purpose
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
def _call(env)
|
23
|
+
code, headers, response = @app.call(env)
|
19
24
|
self.set_accessors(env)
|
25
|
+
[code, headers, [response]]
|
20
26
|
end
|
21
27
|
|
22
28
|
protected
|
23
29
|
|
24
30
|
def set_accessors(env)
|
25
|
-
%w(path request
|
26
|
-
self.send(:"#{name}=", env
|
31
|
+
%w(path site request page content_entry services locale).each do |name|
|
32
|
+
self.send(:"#{name}=", env.fetch("steam.#{name}", nil))
|
27
33
|
end
|
28
34
|
|
29
35
|
env['steam.liquid_assigns'] ||= {}
|
30
|
-
self.liquid_assigns = env
|
31
|
-
end
|
32
|
-
|
33
|
-
def site
|
34
|
-
self.mounting_point.site
|
36
|
+
self.liquid_assigns = env.fetch('steam.liquid_assigns')
|
35
37
|
end
|
36
38
|
|
37
39
|
def params
|
@@ -60,4 +62,4 @@ module Locomotive::Steam
|
|
60
62
|
end
|
61
63
|
|
62
64
|
end
|
63
|
-
end
|
65
|
+
end
|
@@ -20,15 +20,14 @@ module Locomotive::Steam
|
|
20
20
|
protected
|
21
21
|
|
22
22
|
def set_locale!(env)
|
23
|
-
locale =
|
23
|
+
locale = site.default_locale
|
24
24
|
|
25
|
-
if self.path =~ /^(#{self.
|
25
|
+
if self.path =~ /^(#{self.site.locales.join('|')})+(\/|$)/
|
26
26
|
locale = $1
|
27
27
|
self.path = self.path.gsub($1 + $2, '')
|
28
28
|
self.path = 'index' if self.path.blank?
|
29
29
|
end
|
30
30
|
|
31
|
-
Locomotive::Mounter.locale = locale
|
32
31
|
::I18n.locale = locale
|
33
32
|
|
34
33
|
self.log "Detecting locale #{locale.upcase}"
|
@@ -39,4 +38,4 @@ module Locomotive::Steam
|
|
39
38
|
|
40
39
|
end
|
41
40
|
end
|
42
|
-
end
|
41
|
+
end
|
@@ -8,37 +8,38 @@ module Locomotive::Steam
|
|
8
8
|
|
9
9
|
def _call(env)
|
10
10
|
super
|
11
|
-
|
12
|
-
self.set_page!(env)
|
13
|
-
|
11
|
+
set_page!(env)
|
14
12
|
app.call(env)
|
15
13
|
end
|
16
14
|
|
17
15
|
protected
|
18
16
|
|
19
17
|
def set_page!(env)
|
20
|
-
page =
|
21
|
-
|
18
|
+
page = fetch_page env['steam.locale']
|
22
19
|
if page
|
23
|
-
|
20
|
+
log "Found page \"#{page.title}\" [#{page.fullpath}]"
|
24
21
|
end
|
25
22
|
|
26
23
|
env['steam.page'] = page
|
27
24
|
end
|
28
25
|
|
29
|
-
def fetch_page
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
if pages.size > 1
|
38
|
-
self.log "Found multiple pages: #{pages.collect(&:title).join(', ')}"
|
26
|
+
def fetch_page locale
|
27
|
+
decorated(locale) do
|
28
|
+
Locomotive::Models[:pages].current_locale = locale
|
29
|
+
Locomotive::Models[:pages].matching_paths(path_combinations(path)).tap do |pages|
|
30
|
+
if pages.size > 1
|
31
|
+
self.log "Found multiple pages: #{pages.all.collect(&:title).join(', ')}"
|
32
|
+
end
|
33
|
+
end.first
|
39
34
|
end
|
35
|
+
end
|
40
36
|
|
41
|
-
|
37
|
+
def decorated(locale)
|
38
|
+
entity = yield
|
39
|
+
unless entity.nil?
|
40
|
+
Locomotive::Steam::Decorators::PageDecorator.new(
|
41
|
+
Locomotive::Decorators::I18nDecorator.new(entity, locale))
|
42
|
+
end
|
42
43
|
end
|
43
44
|
|
44
45
|
def path_combinations(path)
|
@@ -47,7 +48,6 @@ module Locomotive::Steam
|
|
47
48
|
|
48
49
|
def _path_combinations(segments, can_include_template = true)
|
49
50
|
return nil if segments.empty?
|
50
|
-
|
51
51
|
segment = segments.shift
|
52
52
|
|
53
53
|
(can_include_template ? [segment, '*'] : [segment]).map do |_segment|
|
@@ -6,19 +6,19 @@ module Locomotive::Steam
|
|
6
6
|
def _call(env)
|
7
7
|
super
|
8
8
|
|
9
|
-
if
|
10
|
-
if
|
11
|
-
|
9
|
+
if page
|
10
|
+
if page.redirect?
|
11
|
+
redirect_to(page.redirect_url, page.redirect_type)
|
12
12
|
else
|
13
|
-
type =
|
14
|
-
html =
|
13
|
+
type = page.response_type || 'text/html'
|
14
|
+
html = render_page
|
15
15
|
|
16
|
-
|
16
|
+
log 'Rendered liquid page template'
|
17
17
|
|
18
18
|
[200, { 'Content-Type' => type }, [html]]
|
19
19
|
end
|
20
20
|
else
|
21
|
-
[404, { 'Content-Type' => 'text/html' }, [
|
21
|
+
[404, { 'Content-Type' => 'text/html' }, [render_404]]
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -26,15 +26,42 @@ module Locomotive::Steam
|
|
26
26
|
|
27
27
|
def render_page
|
28
28
|
context = self.locomotive_context
|
29
|
+
# begin
|
30
|
+
# binding.pry
|
31
|
+
render(page, context)
|
32
|
+
# rescue Exception => e
|
33
|
+
|
34
|
+
# raise RendererException.new(e, self.page.title, self.page.template, context)
|
35
|
+
# end
|
36
|
+
end
|
37
|
+
|
38
|
+
def render(page, context)
|
39
|
+
parse(page, context).render(context)
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def parse(page, context)
|
45
|
+
|
46
|
+
options = {
|
47
|
+
page: page,
|
48
|
+
mapper: context.registers[:mapper],
|
49
|
+
error_mode: :strict,
|
50
|
+
count_lines: true
|
51
|
+
}
|
52
|
+
|
29
53
|
begin
|
30
|
-
|
31
|
-
rescue
|
32
|
-
|
54
|
+
::Liquid::Template.parse(page.source(I18n.locale), options)
|
55
|
+
rescue ::Liquid::SyntaxError
|
56
|
+
# do it again on the raw source instead so that the error line matches
|
57
|
+
# the source file.
|
58
|
+
::Liquid::Template.parse(self.template.raw_source, options)
|
33
59
|
end
|
34
60
|
end
|
35
61
|
|
62
|
+
|
36
63
|
def render_404
|
37
|
-
if self.page =
|
64
|
+
if self.page = Locomotive::Models[:pages]['404']
|
38
65
|
self.render_page
|
39
66
|
else
|
40
67
|
'Page not found'
|
@@ -88,8 +115,8 @@ module Locomotive::Steam
|
|
88
115
|
'now' => Time.zone.now,
|
89
116
|
'today' => Date.today,
|
90
117
|
'locale' => I18n.locale.to_s,
|
91
|
-
'default_locale' => self.
|
92
|
-
'locales' => self.
|
118
|
+
'default_locale' => self.site.default_locale.to_s,
|
119
|
+
'locales' => self.site.locales.map(&:to_s),
|
93
120
|
'current_user' => {},
|
94
121
|
'session' => Locomotive::Steam::Liquid::Drops::SessionProxy.new,
|
95
122
|
'steam' => true,
|
@@ -106,7 +133,6 @@ module Locomotive::Steam
|
|
106
133
|
request: self.request,
|
107
134
|
site: self.site,
|
108
135
|
page: self.page,
|
109
|
-
mounting_point: self.mounting_point,
|
110
136
|
services: self.services,
|
111
137
|
inline_editor: false,
|
112
138
|
logger: Locomotive::Common::Logger
|
@@ -116,4 +142,4 @@ module Locomotive::Steam
|
|
116
142
|
end
|
117
143
|
|
118
144
|
end
|
119
|
-
end
|
145
|
+
end
|