locomotivecms_steam 1.5.0.beta1 → 1.5.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -6
  3. data/lib/locomotive/steam/adapters/filesystem.rb +5 -1
  4. data/lib/locomotive/steam/adapters/filesystem/sanitizer.rb +2 -0
  5. data/lib/locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb +3 -0
  6. data/lib/locomotive/steam/adapters/filesystem/sanitizers/page.rb +22 -1
  7. data/lib/locomotive/steam/adapters/filesystem/sanitizers/section.rb +7 -2
  8. data/lib/locomotive/steam/adapters/filesystem/yaml_loader.rb +19 -7
  9. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb +5 -1
  10. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_type.rb +1 -1
  11. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/page.rb +107 -26
  12. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb +8 -0
  13. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/translation.rb +8 -4
  14. data/lib/locomotive/steam/adapters/memory/condition.rb +1 -1
  15. data/lib/locomotive/steam/entities/content_entry.rb +21 -11
  16. data/lib/locomotive/steam/errors.rb +14 -0
  17. data/lib/locomotive/steam/liquid/drops/content_entry_collection.rb +26 -1
  18. data/lib/locomotive/steam/liquid/drops/section_block.rb +3 -7
  19. data/lib/locomotive/steam/liquid/tags/concerns/section.rb +10 -8
  20. data/lib/locomotive/steam/liquid/tags/consume.rb +1 -1
  21. data/lib/locomotive/steam/middlewares/section.rb +0 -4
  22. data/lib/locomotive/steam/middlewares/thread_safe.rb +4 -4
  23. data/lib/locomotive/steam/models/i18n_field.rb +4 -0
  24. data/lib/locomotive/steam/repositories/content_type_field_repository.rb +2 -2
  25. data/lib/locomotive/steam/repositories/content_type_field_select_option_repository.rb +4 -0
  26. data/lib/locomotive/steam/repositories/page_repository.rb +1 -1
  27. data/lib/locomotive/steam/services/content_entry_service.rb +19 -7
  28. data/lib/locomotive/steam/version.rb +1 -1
  29. data/locomotivecms_steam.gemspec +1 -0
  30. data/spec/fixtures/default/data/production/pages/fr/index.json +4 -0
  31. data/spec/fixtures/default/data/production/pages/fr/music.json +8 -0
  32. data/spec/fixtures/default/data/production/pages/fr/unknown.json +8 -0
  33. data/spec/fixtures/default/data/production/site.json +3 -0
  34. data/spec/fixtures/default/data/production/translations.json +6 -0
  35. data/spec/fixtures/default/data/staging/pages/fr/index.json +3 -0
  36. data/spec/unit/adapters/filesystem/sanitizers/section_spec.rb +1 -1
  37. data/spec/unit/adapters/filesystem/yaml_loaders/content_type_spec.rb +5 -1
  38. data/spec/unit/adapters/filesystem/yaml_loaders/page_spec.rb +23 -1
  39. data/spec/unit/adapters/filesystem/yaml_loaders/site_spec.rb +10 -0
  40. data/spec/unit/adapters/filesystem/yaml_loaders/translation_spec.rb +12 -0
  41. data/spec/unit/entities/content_entry_spec.rb +43 -5
  42. data/spec/unit/liquid/tags/consume_spec.rb +24 -0
  43. data/spec/unit/liquid/tags/sections_dropzone_spec.rb +0 -21
  44. data/spec/unit/repositories/content_entry_repository_spec.rb +9 -9
  45. data/spec/unit/repositories/content_type_field_repository_spec.rb +18 -0
  46. data/spec/unit/repositories/page_repository_spec.rb +1 -1
  47. metadata +28 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a416940aeda3a368c649ab613068cb52eca1cab73eb55539c96d7b8669683789
4
- data.tar.gz: 4d82964327f6732779fffc0bc0d58761409b0beeb1dcab05c996a7f9f7191aae
3
+ metadata.gz: 612050310b274060e06a38a72ec026c69b071f3166d6453e2d7f4a8242a3cda1
4
+ data.tar.gz: 5d92a727d6a162872eddd102d560e0c7840a7fc5142a12907f19411e07793955
5
5
  SHA512:
6
- metadata.gz: b705994d68051d9abc826b1fae9968bcf48c3c52d3f74487c56ba704755744115a0081f8c65315ce0f3b5ced476472223474aa6a19a9f79814cc28f56ac65263
7
- data.tar.gz: c7946edfacbaa652feca82ebba5c41a9f674f1b20a7e5b2f7b7b61d4e1c336ae76fcf4a0ac2028b50d1904d11784fd64ac8c903ee2c722aadf3a1185e293c01c
6
+ metadata.gz: e9be228b111d043a33b745dcc7bdf7408cf3651d377183394d7c779067186c0e064f0fed97e66cceceeb791b8b1eeebc61af4e959342b0c6975e5720cf8a7ea7
7
+ data.tar.gz: cc472030e4d96fcd1ca0ef278fb8f9d4a58a502db6a06fad8d1ea1f733272329e057cbe57effa8d18cdb78ffa3bc14d1113181d7ed276d8266d97a65885ffd29
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- locomotivecms_steam (1.5.0.beta1)
15
+ locomotivecms_steam (1.5.0.beta2)
16
16
  RedCloth (~> 4.3.2)
17
17
  autoprefixer-rails (~> 8.0.0)
18
18
  bcrypt (~> 3.1.11)
@@ -29,6 +29,7 @@ PATH
29
29
  mimetype-fu (~> 0.1.2)
30
30
  moneta (~> 1.0.0)
31
31
  morphine (~> 0.1.1)
32
+ multi_json (~> 1.13.1)
32
33
  nokogiri (~> 1.8.2)
33
34
  pony (~> 1.12)
34
35
  rack-cache (~> 1.7.0)
@@ -56,7 +57,7 @@ GEM
56
57
  bcrypt (3.1.12)
57
58
  bson (4.3.0)
58
59
  chronic (0.10.2)
59
- chunky_png (1.3.10)
60
+ chunky_png (1.3.11)
60
61
  codeclimate-test-reporter (0.4.8)
61
62
  simplecov (>= 0.7.1, < 1.0.0)
62
63
  coffee-script (2.4.1)
@@ -97,7 +98,8 @@ GEM
97
98
  haml (5.0.4)
98
99
  temple (>= 0.8.0)
99
100
  tilt
100
- httparty (0.16.2)
101
+ httparty (0.16.3)
102
+ mime-types (~> 3.0)
101
103
  multi_xml (>= 0.5.2)
102
104
  i18n (1.1.0)
103
105
  concurrent-ruby (~> 1.0)
@@ -113,7 +115,7 @@ GEM
113
115
  locomotivecms-liquid (4.0.0)
114
116
  locomotivecms-solid (4.0.1)
115
117
  locomotivecms-liquid (~> 4.0.0)
116
- mail (2.7.0)
118
+ mail (2.7.1)
117
119
  mini_mime (>= 0.1.1)
118
120
  memory_profiler (0.9.11)
119
121
  mime-types (3.1)
@@ -129,7 +131,7 @@ GEM
129
131
  morphine (0.1.1)
130
132
  multi_json (1.13.1)
131
133
  multi_xml (0.6.0)
132
- nokogiri (1.8.4)
134
+ nokogiri (1.8.5)
133
135
  mini_portile2 (~> 2.3.0)
134
136
  nokogumbo (1.5.0)
135
137
  nokogiri
@@ -190,7 +192,7 @@ GEM
190
192
  tins (1.16.3)
191
193
  tzinfo (1.2.5)
192
194
  thread_safe (~> 0.1)
193
- uglifier (4.1.19)
195
+ uglifier (4.1.20)
194
196
  execjs (>= 0.3.0, < 3)
195
197
 
196
198
  PLATFORMS
@@ -116,7 +116,7 @@ module Locomotive::Steam
116
116
 
117
117
  def build_yaml_loaders
118
118
  %i(sites pages content_types content_entries snippets sections translations theme_assets).inject({}) do |memo, name|
119
- memo[name] = build_klass('YAMLLoaders', name).new(site_path)
119
+ memo[name] = build_klass('YAMLLoaders', name).new(site_path, env)
120
120
  memo
121
121
  end
122
122
  end
@@ -137,5 +137,9 @@ module Locomotive::Steam
137
137
  def site_path
138
138
  options.respond_to?(:has_key?) ? options[:path] : options
139
139
  end
140
+
141
+ def env
142
+ (options.respond_to?(:has_key?) ? options[:env] : nil) || :local
143
+ end
140
144
  end
141
145
  end
@@ -1,7 +1,9 @@
1
1
  module Locomotive::Steam
2
2
  module Adapters
3
3
  module Filesystem
4
+
4
5
  module Sanitizer
6
+
5
7
  extend Forwardable
6
8
 
7
9
  def_delegators :@scope, :site, :locale, :locales, :default_locale
@@ -47,6 +47,9 @@ module Locomotive::Steam
47
47
  end
48
48
 
49
49
  def set_id(entity)
50
+ # don't override the id if it was set from a MongoDB dump
51
+ return if entity._id =~ /[a-z0-9]{12,}/
52
+
50
53
  if (slug = entity[:_slug]).respond_to?(:translations)
51
54
  entity[:_id] = slug[locale]
52
55
  else
@@ -20,6 +20,7 @@ module Locomotive::Steam
20
20
  record_id(entity) # required to get the parent_id
21
21
 
22
22
  locales.each do |locale|
23
+ set_automatic_translations(entity, locale)
23
24
  set_default_redirect_type(entity, locale)
24
25
  end
25
26
 
@@ -38,6 +39,7 @@ module Locomotive::Steam
38
39
 
39
40
  use_default_locale_template_path(page, locale)
40
41
 
42
+ # make sure we'll deal with a Hash and not a string
41
43
  transform_sections_content(page, locale)
42
44
  end
43
45
  end
@@ -88,6 +90,20 @@ module Locomotive::Steam
88
90
  page[:fullpath][locale] = fullpath
89
91
  end
90
92
 
93
+ def set_automatic_translations(page, locale)
94
+ return if locale == self.locale
95
+
96
+ if page[:template_path][locale].blank?
97
+ %i(
98
+ title slug fullpath template_path redirect_url
99
+ sections_content sections_dropzone_content
100
+ seo_title meta_description meta_keywords
101
+ ).each do |name|
102
+ page[name][locale] ||= page[name][default_locale]
103
+ end
104
+ end
105
+ end
106
+
91
107
  def depth(page)
92
108
  return page.depth if page.depth
93
109
 
@@ -143,7 +159,12 @@ module Locomotive::Steam
143
159
  [:sections_dropzone_content, :sections_content].each do |name|
144
160
  if content = page[name][locale]
145
161
  return unless content.is_a?(String)
146
- page[name][locale] = JSON.parse(content)
162
+
163
+ begin
164
+ page[name][locale] = MultiJson.load(content)
165
+ rescue MultiJson::ParseError => e
166
+ raise Locomotive::Steam::JsonParsingError.new(e, page.template_path[locale], content)
167
+ end
147
168
  end
148
169
  end
149
170
  end
@@ -21,8 +21,13 @@ module Locomotive::Steam
21
21
 
22
22
  json, template = match[:json], match[:template]
23
23
 
24
- entity.definition = JSON.parse(json)
25
- entity.template = template
24
+ begin
25
+ entity.definition = MultiJson.load(json)
26
+ rescue MultiJson::ParseError => e
27
+ raise Locomotive::Steam::JsonParsingError.new(e, entity.template_path, json)
28
+ end
29
+
30
+ entity.template = template
26
31
  end
27
32
 
28
33
  def raise_parsing_error(entity, content)
@@ -4,20 +4,20 @@ module Locomotive::Steam
4
4
 
5
5
  module YAMLLoader
6
6
 
7
- attr_reader :site_path
7
+ extend Forwardable
8
8
 
9
- def initialize(site_path)
10
- @site_path = site_path
9
+ def_delegators :@scope, :locales, :default_locale
10
+
11
+ attr_reader :site_path, :env
12
+
13
+ def initialize(site_path, env = :local)
14
+ @site_path, @env = site_path, env
11
15
  end
12
16
 
13
17
  def load(scope = nil)
14
18
  @scope = scope
15
19
  end
16
20
 
17
- def default_locale
18
- @scope.default_locale
19
- end
20
-
21
21
  def _load(path, frontmatter = false, &block)
22
22
  if File.exists?(path)
23
23
  yaml = File.open(path).read.force_encoding('utf-8')
@@ -46,6 +46,18 @@ module Locomotive::Steam
46
46
  end
47
47
  end
48
48
 
49
+ def safe_json_load(path)
50
+ return {} unless File.exists?(path)
51
+
52
+ json = File.read(path)
53
+
54
+ begin
55
+ MultiJson.load(json)
56
+ rescue MultiJson::ParseError => e
57
+ raise Locomotive::Steam::JsonParsingError.new(e, path, json)
58
+ end
59
+ end
60
+
49
61
  def template_extensions
50
62
  @extensions ||= %w(liquid haml)
51
63
  end
@@ -110,7 +110,11 @@ module Locomotive
110
110
  end
111
111
 
112
112
  def path
113
- File.join(site_path, 'data')
113
+ return @path if @path # memoization
114
+
115
+ path = File.join(site_path, 'data', env.to_s, 'content_entries')
116
+
117
+ @path = File.exists?(path) ? path : File.join(site_path, 'data') # allow the legacy folder
114
118
  end
115
119
 
116
120
  def content_type
@@ -65,7 +65,7 @@ module Locomotive
65
65
  options.each do |locale, values|
66
66
  values.each_with_index do |name, position|
67
67
  if (option = list.at(position)).nil?
68
- list << { _id: position, name: { locale => name }, position: position }
68
+ list << { _id: position.to_s, name: { locale => name }, position: position }
69
69
  else
70
70
  option[:name][locale] = name
71
71
  end
@@ -8,40 +8,107 @@ module Locomotive
8
8
 
9
9
  include Adapters::Filesystem::YAMLLoader
10
10
 
11
+ # Basically Load all the pages from both the app/views/pages and data/<env>/pages folders
12
+ #
13
+ # The process of loading locally all the pages is pretty complex. Of course, it handles localized pages.
14
+ # It involves 2 main steps.
15
+ #
16
+ # 1/ load all the pages/layouts under app/views/pages. Because of legacy support,
17
+ # we still grab the data from the YAML header.
18
+ #
19
+ # 2/ load the localized content from the data/<env>/pages folder. The content is fetched
20
+ # from the Wagon sync command. 2 kind of pages are stored in this folder:
21
+ # - pages with a not null handle property. We call them core pages. They are not aimed
22
+ # to be deleted. When found, we merge their content with the original page found by process #1
23
+ # - pages without a handle and created from a layout. These pages don't own a liquid template.
24
+ # We just use the liquid template of the layout they belong to.
25
+ #
11
26
  def load(scope)
12
27
  super
28
+
29
+ @pages_by_fullpath = {}
30
+ @pages_by_handle = {}
31
+
32
+ # step #1 (cf description of the method)
13
33
  load_tree
34
+
35
+ # step #2 (cf description of the method)
36
+ load_data
37
+
38
+ @pages_by_fullpath.values
14
39
  end
15
40
 
16
41
  private
17
42
 
18
- def path
19
- @path ||= File.join(site_path, 'app', 'views', 'pages')
43
+ def load_tree
44
+ # load the core pages and layouts from the app/views/pages folder
45
+ each_file do |filepath, fullpath, locale|
46
+ if leaf = @pages_by_fullpath[fullpath]
47
+ update(leaf, filepath, fullpath, locale)
48
+ else
49
+ leaf = build(filepath, fullpath, locale)
50
+ end
51
+
52
+ @pages_by_fullpath[fullpath] = leaf
53
+ @pages_by_handle[leaf[:handle]] = leaf if leaf[:handle].present?
54
+ end
55
+
56
+ each_directory do |filepath, fullpath, locale|
57
+ @pages_by_fullpath[fullpath] ||= build(filepath, fullpath, locale)
58
+ end
20
59
  end
21
60
 
22
- def load_tree
23
- {}.tap do |hash|
24
- each_file do |filepath, fullpath, locale|
61
+ def load_data
62
+ Dir.glob(File.join(data_path, '**', '*.json')).each do |filepath|
63
+ filepath =~ /#{data_path}\/([a-z]+)\//
64
+ data = safe_json_load(filepath)
65
+ locale = $1.to_sym
25
66
 
26
- if leaf = hash[fullpath]
27
- update(leaf, filepath, fullpath, locale)
28
- else
29
- leaf = build(filepath, fullpath, locale)
30
- end
67
+ next unless locales.include?($1.to_sym)
31
68
 
32
- hash[fullpath] = leaf
69
+ if data['handle'].present? # yeah, core page found!
70
+ attributes = @pages_by_handle[data['handle']]
71
+ else
72
+ @pages_by_fullpath[data['fullpath']] ||= {}
73
+ attributes = @pages_by_fullpath[data['fullpath']]
33
74
  end
34
75
 
35
- each_directory do |filepath, fullpath, locale|
36
- hash[fullpath] ||= build(filepath, fullpath, locale)
76
+ complete_attributes_from_data(attributes, data, locale)
77
+ end
78
+ end
79
+
80
+ def complete_attributes_from_data(attributes, data, locale)
81
+ return if attributes.nil? # shouldn't happen (undeleted page? local files out of date?)
82
+
83
+ # this is super important to handle correctly url type settings in sections
84
+ attributes[:_id] = data['id']
85
+
86
+ # required by pages which are not present locally
87
+ attributes[:_fullpath] = data['fullpath']
88
+
89
+ # set the attributes
90
+ %i(
91
+ title slug redirect_url seo_title meta_description meta_keywords
92
+ listed published position
93
+ sections_content sections_dropzone_content editable_elements raw_template
94
+ ).each do |name|
95
+ next if (value = data[name.to_s]).nil?
96
+
97
+ if name == :editable_elements
98
+ update_editable_elements(attributes, value, locale)
99
+ elsif %i(listed published position).include?(name)
100
+ attributes[name] = value
101
+ elsif name != :raw_template || (name == :raw_template && data['handle'].blank?)
102
+ (attributes[name] ||= {})[locale] = value
37
103
  end
38
- end.values
104
+ end
39
105
  end
40
106
 
41
107
  def build(filepath, fullpath, locale)
42
- slug = fullpath.split('/').last
43
- attributes = get_attributes(filepath, fullpath)
108
+ slug = fullpath.split('/').last
109
+ attributes = get_attributes(filepath, fullpath)
44
110
 
111
+ # use first the attributes of the liquid template
45
112
  _attributes = {
46
113
  title: { locale => attributes.delete(:title) || (default_locale == locale ? slug.humanize : nil) },
47
114
  slug: { locale => attributes.delete(:slug) || slug.dasherize },
@@ -50,7 +117,10 @@ module Locomotive
50
117
  _fullpath: fullpath
51
118
  }
52
119
 
53
- [:redirect_url, :seo_title, :meta_description, :meta_keywords].each do |name|
120
+ %i(
121
+ redirect_url seo_title meta_description meta_keywords
122
+ sections_content sections_dropzone_content
123
+ ).each do |name|
54
124
  _attributes[name] = { locale => attributes.delete(name) }
55
125
  end
56
126
 
@@ -58,19 +128,22 @@ module Locomotive
58
128
  end
59
129
 
60
130
  def update(leaf, filepath, fullpath, locale)
61
- slug = fullpath.split('/').last
62
- attributes = get_attributes(filepath, fullpath)
131
+ slug = fullpath.split('/').last
132
+ attributes = get_attributes(filepath, fullpath)
63
133
 
64
- leaf[:title][locale] = attributes.delete(:title) || slug.humanize
65
- leaf[:slug][locale] = attributes.delete(:slug) || slug.dasherize
134
+ leaf[:title][locale] ||= attributes.delete(:title) || slug.humanize
135
+ leaf[:slug][locale] ||= attributes.delete(:slug) || slug.dasherize
66
136
  leaf[:template_path][locale] = template_path(filepath, attributes, locale)
67
137
 
68
- [:redirect_url, :seo_title, :meta_description, :meta_keywords].each do |name|
69
- leaf[name][locale] = attributes.delete(name)
70
- end
71
-
72
138
  update_editable_elements(leaf, attributes.delete(:editable_elements), locale)
73
139
 
140
+ %i(
141
+ redirect_url seo_title meta_description meta_keywords
142
+ sections_content sections_dropzone_content
143
+ ).each do |name|
144
+ leaf[name][locale] ||= attributes.delete(name)
145
+ end
146
+
74
147
  leaf.merge!(attributes)
75
148
  end
76
149
 
@@ -148,7 +221,7 @@ module Locomotive
148
221
 
149
222
  list.each do |name, content|
150
223
  if el = find_editable_element(leaf, name)
151
- el[:content][locale] = content
224
+ el[:content][locale] ||= content
152
225
  else
153
226
  leaf[:editable_elements] << build_editable_element(name, content, locale)
154
227
  end
@@ -175,6 +248,14 @@ module Locomotive
175
248
  attributes[:published] = false
176
249
  end
177
250
 
251
+ def data_path
252
+ File.join(self.site_path, 'data', env.to_s, 'pages')
253
+ end
254
+
255
+ def path
256
+ @path ||= File.join(site_path, 'app', 'views', 'pages')
257
+ end
258
+
178
259
  end
179
260
 
180
261
  end
@@ -17,11 +17,19 @@ module Locomotive
17
17
 
18
18
  attributes[:metafields_schema] = load_metafields_schema
19
19
 
20
+ attributes.merge!(load_from_env)
21
+
20
22
  [attributes]
21
23
  end
22
24
 
23
25
  private
24
26
 
27
+ def load_from_env
28
+ return {} if env == :local
29
+
30
+ safe_json_load(File.join(site_path, 'data', env.to_s, 'site.json')).symbolize_keys
31
+ end
32
+
25
33
  def load_metafields_schema
26
34
  _load(File.join(site_path, 'config', 'metafields_schema.yml'))
27
35
  end
@@ -16,15 +16,19 @@ module Locomotive
16
16
  private
17
17
 
18
18
  def load_array
19
+ all = env == :local ? _load(path) : _load_from_env
20
+
19
21
  [].tap do |array|
20
- if (all = _load(path))
21
- all.each do |key, values|
22
- array << { key: key.to_s, values: HashConverter.to_string(values) }
23
- end
22
+ (all || {}).each do |key, values|
23
+ array << { key: key.to_s, values: HashConverter.to_string(values) }
24
24
  end
25
25
  end
26
26
  end
27
27
 
28
+ def _load_from_env
29
+ safe_json_load(File.join(site_path, 'data', env.to_s, 'translations.json'))
30
+ end
31
+
28
32
  def path
29
33
  File.join(site_path, 'config', 'translations.yml')
30
34
  end
@@ -48,7 +48,7 @@ module Locomotive::Steam
48
48
  protected
49
49
 
50
50
  def entry_value(entry)
51
- value = entry.send(@field) rescue nil # not just it's safe to rely on rescue (hidden errors)
51
+ value = entry.send(@field) rescue nil # TODO: not safe to rely on rescue (hidden errors)
52
52
 
53
53
  if value.respond_to?(:translations)
54
54
  value[@locale]
@@ -95,7 +95,7 @@ module Locomotive::Steam
95
95
  _attributes += content_type.persisted_field_names
96
96
 
97
97
  _attributes.each do |name|
98
- hash[name.to_s] = send(name) rescue nil
98
+ hash[name.to_s] = send(name)
99
99
  end
100
100
 
101
101
  # errors?
@@ -121,6 +121,7 @@ module Locomotive::Steam
121
121
  _cast_value(field)
122
122
  rescue Exception => e
123
123
  Locomotive::Common::Logger.info "[#{content_type.slug}][#{_label}] Unable to cast the \"#{name}\" field, reason: #{e.message}".yellow
124
+ puts e.message
124
125
  nil
125
126
  end
126
127
  end
@@ -190,19 +191,28 @@ module Locomotive::Steam
190
191
  end
191
192
 
192
193
  def _cast_select(field)
193
- if (_value = attributes[:"#{field.name}_id"]).respond_to?(:translations)
194
- # the field is localized, so get the labels in all the locales (2 different locales might point to different options)
195
- # FIXME: dup is used because we want to preserve the original ids
196
- attributes[field.name] = attributes[:"#{field.name}_id"].dup
197
-
198
- _cast_convertor(field.name, true) do |value, locale|
199
- name = field.select_options.find(value)&.name
200
- locale.nil? ? name&.default : name.try(:[], locale)
194
+ options = field.select_options
195
+
196
+ if (_value = @attributes[:"#{field.name}_id"]).respond_to?(:translations)
197
+ # the field is localized, so get the labels in all the locales
198
+ # (2 different locales might point to different options)
199
+ if _value.default
200
+ # unique value for all the locales, so grab the option
201
+ name = options.by_id_or_name(_value.default)&.name
202
+ name&.duplicate(field.name)
203
+ else
204
+ @attributes[field.name] = _value.duplicate(field.name)
205
+
206
+ _cast_convertor(field.name, true) do |value, locale|
207
+ name = options.by_id_or_name(value)&.name
208
+ name.try(:[], locale)
209
+ end
201
210
  end
202
211
  else
203
- # the field is not localized, we only have the id of the option,
212
+ # the field is not localized, we only have the id of the option (or its name if a
213
+ # contact form submission in Wagon for instance),
204
214
  # so just copy the labels (in all the locales) of the matching select option
205
- if name = field.select_options.find(_value)&.name # this should either return an i18nField or nil
215
+ if name = options.by_id_or_name(_value)&.name # this should either return an i18nField or nil
206
216
  attributes[field.name] = name.dup
207
217
  end
208
218
  end
@@ -55,6 +55,20 @@ module Locomotive::Steam
55
55
 
56
56
  end
57
57
 
58
+ class JsonParsingError < ParsingRenderingError
59
+
60
+ def initialize(error, file, source)
61
+ line = if error.message =~ /at line ([0-9]+)/
62
+ $1.to_i
63
+ else
64
+ 0
65
+ end
66
+
67
+ super(error.message, file, source, line, error.backtrace)
68
+ end
69
+
70
+ end
71
+
58
72
  class ActionError < ParsingRenderingError
59
73
 
60
74
  attr_accessor :action
@@ -82,13 +82,38 @@ module Locomotive
82
82
 
83
83
  (content_type_repository.select_options(@content_type, name) || []).map do |option|
84
84
  _option = Locomotive::Steam::Decorators::I18nDecorator.new(option, locale, default_locale)
85
- _option.name
85
+ ContentTypeFieldSelectOption.new(_option)
86
86
  end
87
87
  end
88
88
 
89
89
  end
90
90
 
91
91
  end
92
+
93
+ class ContentTypeFieldSelectOption < ::Liquid::Drop
94
+
95
+ def initialize(option)
96
+ @option = option
97
+ end
98
+
99
+ def id
100
+ @option._id.to_s
101
+ end
102
+
103
+ def name
104
+ @option.name
105
+ end
106
+
107
+ def ==(other_object)
108
+ self.name == other_object
109
+ end
110
+
111
+ def to_s
112
+ self.name
113
+ end
114
+
115
+ end
116
+
92
117
  end
93
118
  end
94
119
  end
@@ -12,7 +12,7 @@ module Locomotive
12
12
  @index = index
13
13
  @definition = section.definition['blocks'].find do |block|
14
14
  block['type'] == type
15
- end
15
+ end || {}
16
16
  end
17
17
 
18
18
  def id
@@ -31,12 +31,8 @@ module Locomotive
31
31
  end
32
32
 
33
33
  def locomotive_attributes
34
- if @context.registers[:live_editing]
35
- value = "section-#{@context['section'].id}-block-#{id}"
36
- %(data-locomotive-block="#{value}")
37
- else
38
- ''
39
- end
34
+ value = "section-#{@context['section'].id}-block-#{id}"
35
+ %(data-locomotive-block="#{value}")
40
36
  end
41
37
 
42
38
  end
@@ -29,16 +29,18 @@ module Locomotive::Steam::Liquid::Tags::Concerns
29
29
  editor_settings_lookup(template.root)
30
30
  end
31
31
 
32
- context.stack do
33
- html = template.render(context)
34
- section = context['section']
32
+ html = template.render(context)
33
+ section = context['section']
34
+ css_class = context['section_css_class']
35
35
 
36
- tag_id = %(id="locomotive-section-#{section.id}")
37
- tag_class = %(class="#{['locomotive-section', section.css_class].compact.join(' ')}")
38
- tag_data = %(data-locomotive-section-type="#{section.type}")
36
+ # we need the section_css_class once
37
+ context.scopes.last.delete('section_css_class')
39
38
 
40
- %(<div #{tag_id} #{tag_class} #{tag_data}>#{html}</div>)
41
- end
39
+ tag_id = %(id="locomotive-section-#{section.id}")
40
+ tag_class = %(class="#{['locomotive-section', section.css_class, css_class].compact.join(' ')}")
41
+ tag_data = %(data-locomotive-section-type="#{section.type}")
42
+
43
+ %(<div #{tag_id} #{tag_class} #{tag_data}>#{html}</div>)
42
44
  end
43
45
 
44
46
  # in order to enable string/text synchronization with the editor:
@@ -89,7 +89,7 @@ module Locomotive
89
89
  end
90
90
 
91
91
  def cache_options
92
- @expires_in.blank? ? { force: true } : { expires_in: @expires_in }
92
+ @expires_in.blank? || @expires_in == 0 ? { force: true } : { expires_in: @expires_in }
93
93
  end
94
94
 
95
95
  def last_response(context)
@@ -18,10 +18,6 @@ module Locomotive::Steam
18
18
  request.get_header('HTTP_LOCOMOTIVE_SECTION_TYPE')
19
19
  end
20
20
 
21
- def section_finder
22
- services.section_finder
23
- end
24
-
25
21
  def render(section_type)
26
22
  document = Liquid::Template.parse(liquid_source(section_type))
27
23
  document.render(liquid_context)
@@ -53,10 +53,6 @@ module Locomotive::Steam::Middlewares
53
53
  @locale ||= env.fetch('steam.locale')
54
54
  end
55
55
 
56
- def liquid_assigns
57
- @liquid_assigns ||= env.fetch('steam.liquid_assigns')
58
- end
59
-
60
56
  def locales
61
57
  site.locales
62
58
  end
@@ -83,6 +79,10 @@ module Locomotive::Steam::Middlewares
83
79
  env['rack.session']
84
80
  end
85
81
 
82
+ def liquid_assigns
83
+ @liquid_assigns ||= env.fetch('steam.liquid_assigns')
84
+ end
85
+
86
86
  def live_editing?
87
87
  !!env['steam.live_editing']
88
88
  end
@@ -57,6 +57,10 @@ module Locomotive::Steam
57
57
  self
58
58
  end
59
59
 
60
+ def duplicate(new_name)
61
+ self.class.new(new_name, self.translations)
62
+ end
63
+
60
64
  alias :__translations__ :translations
61
65
 
62
66
  alias :to_hash :translations
@@ -61,9 +61,9 @@ module Locomotive
61
61
  query { where(required: true) }.all
62
62
  end
63
63
 
64
- def localized_names
64
+ def localized_names(include_select_field_id: true)
65
65
  query { where(localized: true) }.all.map do |field|
66
- field.type == :select ? [field.name, "#{field.name}_id"] : field.name
66
+ field.type == :select && include_select_field_id ? [field.name, "#{field.name}_id"] : field.name
67
67
  end.flatten
68
68
  end
69
69
 
@@ -22,6 +22,10 @@ module Locomotive
22
22
  query { where(name: name) }.first
23
23
  end
24
24
 
25
+ def by_id_or_name(id_or_name)
26
+ find(id_or_name) || by_name(id_or_name)
27
+ end
28
+
25
29
  end
26
30
  end
27
31
  end
@@ -8,7 +8,7 @@ module Locomotive
8
8
  # Entity mapping
9
9
  mapping :pages, entity: Page do
10
10
  localized_attributes :title, :slug, :permalink,
11
- :source, :raw_template, :template_path, :redirect_url, :fullpath,
11
+ :source, :raw_template, :template_path, :data_path, :redirect_url, :fullpath,
12
12
  :sections_content, :sections_dropzone_content,
13
13
  :seo_title, :meta_description, :meta_keywords
14
14
 
@@ -27,7 +27,9 @@ module Locomotive
27
27
  # Warning: do not work with localized and file fields
28
28
  def create(type_slug, attributes, as_json = false)
29
29
  with_repository(type_slug) do |_repository|
30
- entry = _repository.build(clean_attributes(attributes))
30
+ _attributes = prepare_attributes(_repository.content_type, attributes)
31
+
32
+ entry = _repository.build(_attributes)
31
33
 
32
34
  yield(entry) if block_given?
33
35
 
@@ -46,8 +48,10 @@ module Locomotive
46
48
  # Warning: do not work with localized and file fields
47
49
  def update(type_slug, id_or_slug, attributes, as_json = false)
48
50
  with_repository(type_slug) do |_repository|
49
- entry = _repository.by_slug(id_or_slug) || _repository.find(id_or_slug)
50
- decorated_entry = i18n_decorate { entry.change(clean_attributes(attributes)) }
51
+ entry = _repository.by_slug(id_or_slug) || _repository.find(id_or_slug)
52
+ _attributes = prepare_attributes(_repository.content_type, attributes)
53
+
54
+ decorated_entry = i18n_decorate { entry.change(_attributes) }
51
55
 
52
56
  if validate(_repository, decorated_entry)
53
57
  _repository.update(entry)
@@ -61,9 +65,10 @@ module Locomotive
61
65
 
62
66
  def update_decorated_entry(decorated_entry, attributes)
63
67
  with_repository(decorated_entry.content_type) do |_repository|
64
- entry = decorated_entry.__getobj__
68
+ entry = decorated_entry.__getobj__
69
+ _attributes = prepare_attributes(_repository.content_type, attributes)
65
70
 
66
- entry.change(clean_attributes(attributes))
71
+ entry.change(_attributes)
67
72
 
68
73
  _repository.update(entry)
69
74
 
@@ -117,12 +122,19 @@ module Locomotive
117
122
  as_json ? entry.as_json : entry
118
123
  end
119
124
 
120
- def clean_attributes(attributes)
125
+ def prepare_attributes(content_type, attributes)
126
+ select_field_names = content_type.fields.selects.map(&:name)
127
+
121
128
  attributes.each do |key, value|
122
129
  next unless value.is_a?(String)
123
130
  attributes[key] = Sanitize.clean(value, Sanitize::Config::BASIC)
124
131
  end
125
- attributes
132
+
133
+ # special case: select fields. <name> becomes <name>_id
134
+ attributes.map do |key, value|
135
+ _key = select_field_names.include?(key.to_s) ? "#{key}_id" : key
136
+ [_key, value]
137
+ end.to_h
126
138
  end
127
139
 
128
140
  def validate(_repository, 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.5.0.beta1'
6
+ VERSION = '1.5.0.beta2'
7
7
  end
8
8
  end
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'httparty', '~> 0.16.0'
28
28
  spec.add_dependency 'chronic', '~> 0.10.2'
29
29
  spec.add_dependency 'bcrypt', '~> 3.1.11'
30
+ spec.add_dependency 'multi_json', '~> 1.13.1'
30
31
 
31
32
  spec.add_dependency 'rack-rewrite', '~> 1.5.1'
32
33
  spec.add_dependency 'rack-cache', '~> 1.7.0'
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Ma page d'accueil en production",
3
+ "fullpath": "index"
4
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "title": "Our music",
3
+ "handle": "our-music",
4
+ "fullpath": "our-music",
5
+ "editable_elements": {
6
+ "content/introduction": "Simple content"
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "title": "A page created in the back-office",
3
+ "fullpath": "unknown",
4
+ "listed": true,
5
+ "published": true,
6
+ "position": 42,
7
+ "raw_template": "Hello world"
8
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "My awesome site"
3
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hello_world": {
3
+ "en": "Hello world",
4
+ "fr": "Bonjour le monde"
5
+ }
6
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "invalid json
3
+ }
@@ -57,7 +57,7 @@ LIQUID
57
57
  let(:template_path) { 'spec/fixtures/errors/section_bad_json_content.liquid' }
58
58
 
59
59
  it 'should throw an error' do
60
- expect { subject }.to raise_error(JSON::ParserError)
60
+ expect { subject }.to raise_error(Locomotive::Steam::JsonParsingError)
61
61
  end
62
62
  end
63
63
  end
@@ -29,7 +29,11 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentType do
29
29
 
30
30
  subject { loader.send(:build_select_options_from_hash, options) }
31
31
 
32
- it { is_expected.to eq [{ _id: 0, name: { en: 'General', fr: 'Général' }, position: 0 }, { _id: 1, name: { en: 'Gigs', fr: 'Concerts' }, position: 1 }, { _id: 2, name: { en: 'Bands', fr: 'Groupes' }, position: 2 }] }
32
+ it { is_expected.to eq [
33
+ { _id: '0', name: { en: 'General', fr: 'Général' }, position: 0 },
34
+ { _id: '1', name: { en: 'Gigs', fr: 'Concerts' }, position: 1 },
35
+ { _id: '2', name: { en: 'Bands', fr: 'Groupes' }, position: 2 }]
36
+ }
33
37
 
34
38
  end
35
39
 
@@ -10,7 +10,7 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Page do
10
10
 
11
11
  describe '#load' do
12
12
 
13
- let(:scope) { instance_double('Scope', locale: :fr, default_locale: :en) }
13
+ let(:scope) { instance_double('Scope', locale: :fr, default_locale: :en, locales: [:en, :fr]) }
14
14
 
15
15
  subject { loader.load(scope).sort { |a, b| a[:_fullpath] <=> b[:_fullpath] } }
16
16
 
@@ -25,6 +25,28 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Page do
25
25
  expect(subject[25][:template_path]).to eq(en: false)
26
26
  end
27
27
 
28
+ context 'a different environment' do
29
+
30
+ let(:env) { :production }
31
+ let(:loader) { described_class.new(site_path, env) }
32
+
33
+ it 'completes the data with the ones from the production environment' do
34
+ expect(subject.size).to eq 36
35
+ expect(subject[21][:title]).to eq(en: 'Home page', fr: "Ma page d'accueil en production")
36
+ end
37
+
38
+ describe 'invalid json' do
39
+
40
+ let(:env) { :staging }
41
+
42
+ it 'raises a parsing exception' do
43
+ expect { subject }.to raise_exception(Locomotive::Steam::JsonParsingError)
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
28
50
  end
29
51
 
30
52
  end
@@ -24,6 +24,16 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Site do
24
24
 
25
25
  end
26
26
 
27
+ context 'a different environment' do
28
+
29
+ let(:loader) { described_class.new(site_path, :production) }
30
+
31
+ it 'completes the data with the ones from the production environment' do
32
+ expect(subject[:name]).to eq('My awesome site')
33
+ end
34
+
35
+ end
36
+
27
37
  end
28
38
 
29
39
  end
@@ -20,6 +20,18 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Translation do
20
20
  expect(subject.first[:values]).to eq({ 'en' => 'Powered by', 'fr' => 'Propulsé par' })
21
21
  end
22
22
 
23
+ context 'a different environment' do
24
+
25
+ let(:loader) { described_class.new(site_path, :production) }
26
+
27
+ it 'replaces the data with the ones from the production environment' do
28
+ expect(subject.size).to eq 1
29
+ expect(subject.first[:key]).to eq('hello_world')
30
+ expect(subject.first[:values]).to eq('en' => 'Hello world', 'fr' => 'Bonjour le monde')
31
+ end
32
+
33
+ end
34
+
23
35
  end
24
36
 
25
37
  end
@@ -230,11 +230,49 @@ describe Locomotive::Steam::ContentEntry do
230
230
  end
231
231
 
232
232
  context 'a select' do
233
- let(:option) { instance_double('SelectOption', name: { en: 'Category #1', fr: 'Categorie #1' }) }
234
- let(:field) { instance_double('Field', name: :my_field, type: :select, select_options: instance_double('SelectOptions')) }
235
- let(:attributes) { { my_field_id: 42 } }
236
- before { expect(field.select_options).to receive(:find).with(42).and_return(option) }
237
- it { is_expected.to eq({ en: 'Category #1', fr: 'Categorie #1' }) }
233
+ let(:translations) { instance_double('Translations', translations: { en: 'Category #1', fr: 'Categorie #1' }) }
234
+ let(:option) { instance_double('SelectOption', name: translations) }
235
+ let(:options) { instance_double('SelectOptions') }
236
+ let(:field) { instance_double('Field', name: :my_field, type: :select, select_options: options) }
237
+ let(:attributes) { { my_field_id: attribute } }
238
+
239
+ context 'the attribute is not localized' do
240
+
241
+ let(:option) { instance_double('SelectOption', name: 'Category #1') }
242
+ let(:attribute) { 42 }
243
+
244
+ before { expect(options).to receive(:by_id_or_name).with(42).and_return(option) }
245
+
246
+ it { expect(subject).to eq('Category #1') }
247
+ end
248
+
249
+ context 'the attribute is localized' do
250
+
251
+ context 'the attribute has values in all the locales' do
252
+
253
+ let(:attribute) { instance_double('FieldValue', default: nil, translations: true) }
254
+
255
+ before do
256
+ expect(attribute).to receive(:duplicate).with(:my_field).and_return(translations)
257
+ expect(translations).to receive(:apply).and_return(translations)
258
+ end
259
+
260
+ it { expect(subject.translations).to eq({ en: 'Category #1', fr: 'Categorie #1' }) }
261
+
262
+ end
263
+
264
+ context 'the attribute has the same value in all the locales' do
265
+
266
+ let(:attribute) { instance_double('FieldValue', default: 42, translations: true) }
267
+
268
+ before { expect(translations).to receive(:duplicate).with(:my_field).and_return(translations) }
269
+ before { expect(options).to receive(:by_id_or_name).with(42).and_return(option) }
270
+
271
+ it { expect(subject.translations).to eq({ en: 'Category #1', fr: 'Categorie #1' }) }
272
+
273
+ end
274
+
275
+ end
238
276
  end
239
277
 
240
278
  context 'a json' do
@@ -80,6 +80,30 @@ describe Locomotive::Steam::Liquid::Tags::Consume do
80
80
 
81
81
  end
82
82
 
83
+ describe 'with an expires_in option' do
84
+
85
+ let(:assigns) { { 'secret_password' => 'bar' } }
86
+ let(:source) { "{% consume blog from \"http://blog.locomotiveapp.org/api/read\", username: 'foo', password: secret_password, expires_in: #{expires_in} %}{{ blog.title }}{% endconsume %}" }
87
+ let(:expires_in) { 42 }
88
+
89
+ it 'passes the expires_in value to the cache' do
90
+ expect(services.cache).to receive(:fetch).with('Steam-consume-d1249cd56af82e108d383f981ad953347dbb94dc', { expires_in: 42 }).and_return('Locomotive rocks!')
91
+ is_expected.to eq 'Locomotive rocks!'
92
+ end
93
+
94
+ describe 'expires_in set to 0 (so basically, meaning non cache at all)' do
95
+
96
+ let(:expires_in) { 0 }
97
+
98
+ it "doesn't pass the expires_in value to the cache" do
99
+ expect(services.cache).to receive(:fetch).with('Steam-consume-d1249cd56af82e108d383f981ad953347dbb94dc', { force: true }).and_return('Locomotive rocks!')
100
+ is_expected.to eq 'Locomotive rocks!'
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
83
107
  describe 'timeout' do
84
108
 
85
109
  let(:response) { { 'title' => 'first response' } }
@@ -80,27 +80,6 @@ describe Locomotive::Steam::Liquid::Tags::SectionsDropzone do
80
80
  .strip.gsub(/\n\s+/, '')
81
81
  end
82
82
 
83
- context 'live editing is off' do
84
-
85
- let(:live_editing) { false }
86
-
87
- it 'renders the list of sections' do
88
- is_expected.to eq <<-HTML
89
- <div class="locomotive-sections">
90
- <div id="locomotive-section-dropzone-0" class="locomotive-section" data-locomotive-section-type="hero">
91
- <h1>Hello world</h1>
92
- </div>
93
- <div id="locomotive-section-dropzone-1" class="locomotive-section" data-locomotive-section-type="slideshow">
94
- <div ><p>Slide 1</p></div>
95
- <div ><p>Slide 2</p></div>
96
- </div>
97
- </div>
98
- HTML
99
- .strip.gsub(/\n\s+/, '')
100
- end
101
-
102
- end
103
-
104
83
  end
105
84
 
106
85
  end
@@ -248,27 +248,27 @@ describe Locomotive::Steam::ContentEntryRepository do
248
248
 
249
249
  let(:options) {
250
250
  [
251
- instance_double('SelectOption1', _id: 0, name: instance_double('I18nField', :[] => 'cooking', translations: { 'en' => 'cooking' })),
252
- instance_double('SelectOption2', _id: 1, name: instance_double('I18nField', :[] => 'wine', translations: { 'en' => 'wine' })),
253
- instance_double('SelectOption3', _id: 2, name: instance_double('I18nField', :[] => 'bread', translations: { 'en' => 'bread' }))
251
+ instance_double('SelectOption1', _id: '0', name: instance_double('I18nField', :[] => 'cooking', translations: { 'en' => 'cooking' })),
252
+ instance_double('SelectOption2', _id: '1', name: instance_double('I18nField', :[] => 'wine', translations: { 'en' => 'wine' })),
253
+ instance_double('SelectOption3', _id: '2', name: instance_double('I18nField', :[] => 'bread', translations: { 'en' => 'bread' }))
254
254
  ]
255
255
  }
256
256
 
257
257
  let(:entries) do
258
258
  [
259
- { content_type_id: 1, _position: 0, _label: 'Recipe #1', category_id: { 'en' => 0 } },
260
- { content_type_id: 1, _position: 1, _label: 'Recipe #2', category_id: { 'en' => 2 } },
261
- { content_type_id: 1, _position: 2, _label: 'Recipe #3', category_id: { 'en' => 2 } },
262
- { content_type_id: 1, _position: 3, _label: 'Recipe #4', category_id: { 'en' => 42 } } # unknown category
259
+ { content_type_id: 1, _position: 0, _label: 'Recipe #1', category_id: { 'en' => '0' } },
260
+ { content_type_id: 1, _position: 1, _label: 'Recipe #2', category_id: { 'en' => '2' } },
261
+ { content_type_id: 1, _position: 2, _label: 'Recipe #3', category_id: { 'en' => '2' } },
262
+ { content_type_id: 1, _position: 3, _label: 'Recipe #4', category_id: { 'en' => '42' } } # unknown category
263
263
  ]
264
264
  end
265
265
 
266
266
  before {
267
267
  allow(content_type_repository).to receive(:select_options).and_return(options)
268
268
  %w(cooking wine bread).each_with_index do |name, position|
269
- allow(fields[:category].select_options).to receive(:find).with(position).and_return(options.at(position))
269
+ allow(fields[:category].select_options).to receive(:by_id_or_name).with(position.to_s).and_return(options.at(position))
270
270
  end
271
- allow(fields[:category].select_options).to receive(:find).with(42).and_return(nil)
271
+ allow(fields[:category].select_options).to receive(:by_id_or_name).with('42').and_return(nil)
272
272
  }
273
273
 
274
274
  it { expect(subject.size).to eq 4 }
@@ -80,4 +80,22 @@ describe Locomotive::Steam::ContentTypeFieldRepository do
80
80
 
81
81
  end
82
82
 
83
+ describe '#localized_names' do
84
+
85
+ let(:collection) { [{ name: 'name', type: 'string', localized: true }, { name: 'picture', type: 'file' }, { name: 'category', type: 'select', localized: true }] }
86
+
87
+ subject { repository.localized_names }
88
+
89
+ it { expect(subject).to eq(['name', 'category', 'category_id']) }
90
+
91
+ context 'without the select field id' do
92
+
93
+ subject { repository.localized_names(include_select_field_id: false) }
94
+
95
+ it { expect(subject).to eq(['name', 'category']) }
96
+
97
+ end
98
+
99
+ end
100
+
83
101
  end
@@ -71,7 +71,7 @@ describe Locomotive::Steam::PageRepository do
71
71
  it { expect(subject.templatized?).to eq true }
72
72
  it { expect(subject.content_type_id).to eq 'articles' }
73
73
  it { expect(subject.slug[:en]).to eq 'comments' }
74
- it { expect(subject.slug[:fr]).to eq nil }
74
+ it { expect(subject.slug[:fr]).to eq 'comments' }
75
75
  it { expect(subject.fullpath[:en]).to eq 'articles/content_type_template/comments' }
76
76
 
77
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: locomotivecms_steam
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0.beta1
4
+ version: 1.5.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Didier Lafforgue
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-11-30 00:00:00.000000000 Z
14
+ date: 2018-12-10 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -153,6 +153,20 @@ dependencies:
153
153
  - - "~>"
154
154
  - !ruby/object:Gem::Version
155
155
  version: 3.1.11
156
+ - !ruby/object:Gem::Dependency
157
+ name: multi_json
158
+ requirement: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - "~>"
161
+ - !ruby/object:Gem::Version
162
+ version: 1.13.1
163
+ type: :runtime
164
+ prerelease: false
165
+ version_requirements: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - "~>"
168
+ - !ruby/object:Gem::Version
169
+ version: 1.13.1
156
170
  - !ruby/object:Gem::Dependency
157
171
  name: rack-rewrite
158
172
  requirement: !ruby/object:Gem::Requirement
@@ -709,7 +723,13 @@ files:
709
723
  - spec/fixtures/default/data/bands.yml
710
724
  - spec/fixtures/default/data/events.yml
711
725
  - spec/fixtures/default/data/messages.yml
726
+ - spec/fixtures/default/data/production/pages/fr/index.json
727
+ - spec/fixtures/default/data/production/pages/fr/music.json
728
+ - spec/fixtures/default/data/production/pages/fr/unknown.json
729
+ - spec/fixtures/default/data/production/site.json
730
+ - spec/fixtures/default/data/production/translations.json
712
731
  - spec/fixtures/default/data/songs.yml
732
+ - spec/fixtures/default/data/staging/pages/fr/index.json
713
733
  - spec/fixtures/default/data/updates.yml
714
734
  - spec/fixtures/default/public/fonts/chunkfive-webfont.eot
715
735
  - spec/fixtures/default/public/fonts/chunkfive-webfont.svg
@@ -1007,7 +1027,13 @@ test_files:
1007
1027
  - spec/fixtures/default/data/bands.yml
1008
1028
  - spec/fixtures/default/data/events.yml
1009
1029
  - spec/fixtures/default/data/messages.yml
1030
+ - spec/fixtures/default/data/production/pages/fr/index.json
1031
+ - spec/fixtures/default/data/production/pages/fr/music.json
1032
+ - spec/fixtures/default/data/production/pages/fr/unknown.json
1033
+ - spec/fixtures/default/data/production/site.json
1034
+ - spec/fixtures/default/data/production/translations.json
1010
1035
  - spec/fixtures/default/data/songs.yml
1036
+ - spec/fixtures/default/data/staging/pages/fr/index.json
1011
1037
  - spec/fixtures/default/data/updates.yml
1012
1038
  - spec/fixtures/default/public/fonts/chunkfive-webfont.eot
1013
1039
  - spec/fixtures/default/public/fonts/chunkfive-webfont.svg