scrivito_sdk 1.1.1 → 1.2.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scrivito/blobs_controller.rb +7 -0
  3. data/app/controllers/scrivito/objs_controller.rb +0 -6
  4. data/app/controllers/scrivito/ui_controller.rb +2 -0
  5. data/app/views/scrivito/blobs/{activate_upload.json.jbuilder → blob.json.jbuilder} +0 -0
  6. data/config/ca-bundle.crt +1 -1
  7. data/config/precedence_routes.rb +1 -1
  8. data/lib/assets/javascripts/scrivito_ui.js +20072 -19687
  9. data/lib/assets/stylesheets/scrivito.css +1 -1
  10. data/lib/assets/stylesheets/scrivito_ui.css +1 -1
  11. data/lib/generators/scrivito/install/install_generator.rb +2 -8
  12. data/lib/generators/scrivito/install/templates/app/views/download/details.html.erb +11 -0
  13. data/lib/generators/scrivito/install/templates/app/views/headline_widget/thumbnail.html.erb +1 -1
  14. data/lib/generators/scrivito/install/templates/app/views/image/details.html.erb +17 -0
  15. data/lib/generators/scrivito/install/templates/app/views/image_widget/thumbnail.html.erb +1 -1
  16. data/lib/generators/scrivito/install/templates/app/views/page/details.html.erb +4 -2
  17. data/lib/generators/scrivito/install/templates/app/views/page/thumbnail.html.erb +1 -3
  18. data/lib/generators/scrivito/install/templates/app/views/text_widget/thumbnail.html.erb +2 -2
  19. data/lib/generators/scrivito/page/page_generator.rb +8 -0
  20. data/lib/generators/scrivito/page/templates/details.html.erb +4 -2
  21. data/lib/generators/scrivito/page/templates/thumbnail.html.erb +1 -3
  22. data/lib/generators/scrivito/widget/templates/details.html.erb +4 -2
  23. data/lib/generators/scrivito/widget/templates/show.html.erb +1 -2
  24. data/lib/generators/scrivito/widget/templates/thumbnail.html.erb +1 -3
  25. data/lib/generators/scrivito/widget/widget_generator.rb +0 -4
  26. data/lib/scrivito/attribute_content.rb +44 -15
  27. data/lib/scrivito/attribute_definition.rb +59 -3
  28. data/lib/scrivito/basic_obj.rb +11 -18
  29. data/lib/scrivito/basic_widget.rb +42 -0
  30. data/lib/scrivito/binary.rb +5 -5
  31. data/lib/scrivito/cache_middleware.rb +13 -17
  32. data/lib/scrivito/class_collection.rb +1 -1
  33. data/lib/scrivito/client_attribute_serializer.rb +5 -1
  34. data/lib/scrivito/cms_backend.rb +43 -60
  35. data/lib/scrivito/cms_data_cache.rb +18 -14
  36. data/lib/scrivito/cms_field_tag.rb +2 -2
  37. data/lib/scrivito/cms_rest_api.rb +9 -8
  38. data/lib/scrivito/cms_routing.rb +1 -1
  39. data/lib/scrivito/configuration.rb +15 -4
  40. data/lib/scrivito/connection_manager.rb +29 -23
  41. data/lib/scrivito/model_library.rb +43 -11
  42. data/lib/scrivito/obj_collection.rb +1 -1
  43. data/lib/scrivito/obj_params_parser.rb +1 -19
  44. data/lib/scrivito/obj_search_enumerator/query_executor.rb +1 -1
  45. data/lib/scrivito/obj_search_enumerator.rb +1 -1
  46. data/lib/scrivito/ui_config.rb +13 -2
  47. data/lib/scrivito/widget_collection.rb +1 -1
  48. data/lib/scrivito/workspace.rb +25 -26
  49. data/lib/scrivito_sdk.rb +67 -40
  50. metadata +21 -8
  51. data/lib/generators/scrivito/install/templates/app/views/download/embed.html.erb +0 -1
  52. data/lib/generators/scrivito/install/templates/app/views/image/embed.html.erb +0 -1
  53. data/lib/scrivito/widget_garbage_collection.rb +0 -97
@@ -1,45 +1,8 @@
1
1
  module Scrivito
2
- class CmsBackend
2
+ module CmsBackend
3
3
  VALID_INDEX_NAMES = %w[id path ppath permalink].freeze
4
4
 
5
- class << self
6
- def instance
7
- @instance ||= new
8
- end
9
- end
10
-
11
- def initialize
12
- @query_counter = 0
13
- @caching = true
14
- end
15
-
16
- def begin_caching
17
- @caching = true
18
- end
19
-
20
- def end_caching
21
- CmsDataCache.clear_request_cache
22
- @caching = false
23
- end
24
-
25
- def clear_cache
26
- CmsDataCache.clear_request_cache
27
- end
28
-
29
- def caching?
30
- !!@caching
31
- end
32
-
33
- def query_counter
34
- @query_counter
35
- end
36
-
37
- # For test purpose only.
38
- def reset_query_counter!
39
- @query_counter = 0
40
- end
41
-
42
- def find_workspace_data_from_cache(id)
5
+ def self.find_workspace_data_from_cache(id)
43
6
  cached_workspace_state = CmsDataCache.read_workspace_state(id)
44
7
  cached_data_tag = cached_workspace_state.try(:second)
45
8
  cached_content_state_id = cached_workspace_state.try(:first)
@@ -51,7 +14,7 @@ module Scrivito
51
14
  end
52
15
  end
53
16
 
54
- def find_workspace_data_by_id(id, timeout=nil)
17
+ def self.find_workspace_data_by_id(id, timeout=nil)
55
18
  options = timeout ? {timeout: timeout} : {}
56
19
 
57
20
  cached_workspace_state = CmsDataCache.read_workspace_state(id)
@@ -82,7 +45,7 @@ module Scrivito
82
45
  end
83
46
  end
84
47
 
85
- def find_obj_data_by(revision, index, keys)
48
+ def self.find_obj_data_by(revision, index, keys)
86
49
  index = index.to_s
87
50
 
88
51
  if index == "id"
@@ -94,7 +57,7 @@ module Scrivito
94
57
  end
95
58
  end
96
59
 
97
- def find_blob_data(id, access, verb, options = {})
60
+ def self.find_blob_data(id, access, verb, options = {})
98
61
  if blob_data = find_blob_data_from_cache(id, access, verb, options)
99
62
  blob_data
100
63
  else
@@ -105,12 +68,12 @@ module Scrivito
105
68
  end
106
69
  end
107
70
 
108
- def find_blob_data_from_cache(id, access, verb, options)
71
+ def self.find_blob_data_from_cache(id, access, verb, options)
109
72
  cache_key = blob_data_cache_key(normalize_blob_id(id), access, verb, options)
110
73
  CmsDataCache.cache.read(cache_key)
111
74
  end
112
75
 
113
- def find_binary_meta_data(blob_id)
76
+ def self.find_binary_meta_data(blob_id)
114
77
  blob_id = normalize_blob_id(blob_id)
115
78
  cache_key = "binary_meta_data/#{blob_id}"
116
79
  if meta_data = CmsDataCache.cache.read(cache_key)
@@ -122,7 +85,7 @@ module Scrivito
122
85
  end
123
86
  end
124
87
 
125
- def search_objs(workspace, params)
88
+ def self.search_objs(workspace, params)
126
89
  cache_index = 'search'
127
90
  cache_key = params.to_param
128
91
  cache = Backend::ObjDataCache.view_for_revision(workspace.revision)
@@ -137,23 +100,32 @@ module Scrivito
137
100
  result
138
101
  end
139
102
 
140
- def create_obj(workspace_id, attributes)
103
+ def self.create_obj(workspace_id, attributes)
141
104
  write_obj(:post, "/workspaces/#{workspace_id}/objs", attributes)
142
105
  end
143
106
 
144
- def update_obj(workspace_id, obj_id, attributes)
107
+ def self.update_obj(workspace_id, obj_id, attributes)
145
108
  write_obj(:put, "/workspaces/#{workspace_id}/objs/#{obj_id}", attributes)
146
109
  end
147
110
 
148
- private
111
+ # For test purpose only.
112
+ def self.query_counter
113
+ @query_counter
114
+ end
115
+
116
+ # For test purpose only.
117
+ def self.reset_query_counter!
118
+ @query_counter = 0
119
+ end
149
120
 
150
- def write_obj(verb, path, attributes)
121
+ def self.write_obj(verb, path, attributes)
151
122
  Backend::ObjDataFromRest.new(CmsRestApi.task_unaware_request(verb, path, attributes))
152
123
  end
124
+ private_class_method :write_obj
153
125
 
154
- def update_workspace_cache(id, cached_data_tag, changed_workspace, options)
155
- if changed_workspace
156
- workspace_data = changed_workspace
126
+ def self.update_workspace_cache(id, cached_data_tag, workspace, options)
127
+ if workspace
128
+ workspace_data = workspace
157
129
  else
158
130
  if cached_workspace_data = fetch_cached_data_by_tag(cached_data_tag)
159
131
  workspace_data = cached_workspace_data
@@ -167,16 +139,19 @@ module Scrivito
167
139
 
168
140
  [workspace_data, workspace_data_tag]
169
141
  end
142
+ private_class_method :update_workspace_cache
170
143
 
171
- def fetch_cached_data_by_tag(data_tag)
144
+ def self.fetch_cached_data_by_tag(data_tag)
172
145
  data_tag && CmsDataCache.read_data_from_tag(data_tag)
173
146
  end
147
+ private_class_method :fetch_cached_data_by_tag
174
148
 
175
- def build_workspace_data(raw_data, content_state_id)
149
+ def self.build_workspace_data(raw_data, content_state_id)
176
150
  WorkspaceData.new(raw_data.merge('content_state_id' => content_state_id))
177
151
  end
152
+ private_class_method :build_workspace_data
178
153
 
179
- def update_obj_cache(workspace_id, cached_csid, changes)
154
+ def self.update_obj_cache(workspace_id, cached_csid, changes)
180
155
  objs = changes["objs"]
181
156
  if objs.present? && objs != "*"
182
157
  last_state = Backend::ContentStateNode.find(cached_csid)
@@ -189,14 +164,18 @@ module Scrivito
189
164
  end
190
165
  end
191
166
  end
167
+ private_class_method :update_obj_cache
192
168
 
193
- def request_search_result_from_backend(workspace, params)
169
+ def self.request_search_result_from_backend(workspace, params)
194
170
  params = params.merge(consistent_with: workspace.content_state_id)
195
171
  CmsRestApi.get("workspaces/#{workspace.id}/objs/search", params)
196
172
  end
173
+ private_class_method :request_search_result_from_backend
197
174
 
198
- def request_blob_datas_from_backend(id, options)
175
+ def self.request_blob_datas_from_backend(id, options)
176
+ @query_counter ||= 0
199
177
  @query_counter += 1
178
+
200
179
  case
201
180
  when transformation_definition = options[:transformation_definition]
202
181
  CmsRestApi.get("blobs/#{id}/transform", transformation: transformation_definition)
@@ -206,8 +185,9 @@ module Scrivito
206
185
  CmsRestApi.get("blobs/#{id}")
207
186
  end
208
187
  end
188
+ private_class_method :request_blob_datas_from_backend
209
189
 
210
- def store_blob_datas_in_cache(id, options, blob_datas)
190
+ def self.store_blob_datas_in_cache(id, options, blob_datas)
211
191
  %w[public_access private_access].each do |access|
212
192
  %w[get head].each do |verb|
213
193
  if access_blob_data = blob_datas[access]
@@ -219,8 +199,9 @@ module Scrivito
219
199
  end
220
200
  end
221
201
  end
202
+ private_class_method :store_blob_datas_in_cache
222
203
 
223
- def blob_data_cache_key(id, access, verb, options)
204
+ def self.blob_data_cache_key(id, access, verb, options)
224
205
  cache_key = "blob_data/#{id}/#{access}/#{verb}"
225
206
 
226
207
  if transformation_definition = options[:transformation_definition]
@@ -233,9 +214,11 @@ module Scrivito
233
214
 
234
215
  cache_key
235
216
  end
217
+ private_class_method :blob_data_cache_key
236
218
 
237
- def normalize_blob_id(id)
219
+ def self.normalize_blob_id(id)
238
220
  CmsRestApi.normalize_path_component(id)
239
221
  end
222
+ private_class_method :normalize_blob_id
240
223
  end
241
224
  end
@@ -5,29 +5,29 @@ module CmsDataCache
5
5
  VERSION = 'v3'.freeze
6
6
 
7
7
  class << self
8
- attr_reader :second_level_cache
9
- attr_writer :cache_path
10
-
11
8
  def cache
12
- @cache_chain ||= Cache::RamStore.new(next_store: first_level_cache, cache_prefix: VERSION)
9
+ Thread.current[:scrivito_cms_data_cache_chain] ||=
10
+ Cache::RamStore.new(next_store: first_level_cache, cache_prefix: VERSION)
13
11
  end
14
12
 
15
13
  def cache_path=(path)
16
14
  clear_cache_chain
17
- @cache_path = path
15
+ Thread.current[:scrivito_cms_data_cache_path] = path
18
16
  end
19
17
 
20
18
  def first_level_cache
21
- @first_level_cache ||= Cache::FileStore.new(path: @cache_path, next_store: second_level_cache)
22
- end
23
-
24
- def clear_request_cache
25
- cache.clear
19
+ cache_path = Thread.current[:scrivito_cms_data_cache_path]
20
+ Thread.current[:scrivito_cms_data_first_level_cache] ||=
21
+ Cache::FileStore.new(path: cache_path, next_store: second_level_cache)
26
22
  end
27
23
 
28
24
  def second_level_cache=(cache_store)
29
25
  clear_cache_chain
30
- @second_level_cache = cache_store
26
+ Thread.current[:scrivito_cms_data_second_level_cache] = cache_store
27
+ end
28
+
29
+ def second_level_cache
30
+ Thread.current[:scrivito_cms_data_second_level_cache]
31
31
  end
32
32
 
33
33
  SCHEMA = {
@@ -77,12 +77,16 @@ module CmsDataCache
77
77
  read_tag_data(tag)
78
78
  end
79
79
 
80
+ def clear_request_cache
81
+ cache.clear
82
+ end
83
+
80
84
  private
81
85
 
82
86
  def clear_cache_chain
83
- @cache_chain = nil
84
- @first_level_cache = nil
85
- @second_level_cache = nil
87
+ Thread.current[:scrivito_cms_data_cache_chain] = nil
88
+ Thread.current[:scrivito_cms_data_first_level_cache] = nil
89
+ Thread.current[:scrivito_cms_data_second_level_cache] = nil
86
90
  end
87
91
  end
88
92
  end
@@ -46,7 +46,7 @@ class CmsFieldTag < Struct.new(:view, :tag_name, :obj_or_widget, :editing_option
46
46
  'field-obj-class' => obj_or_widget.obj_class,
47
47
  'field-type' => field_type,
48
48
  'private-editor' => editing_options[:editor],
49
- 'private-field-allowed-values' => allowed_values,
49
+ 'private-field-allowed-values' => valid_values,
50
50
  'private-field-workspace-id' => current_workspace_id,
51
51
  }
52
52
 
@@ -158,7 +158,7 @@ class CmsFieldTag < Struct.new(:view, :tag_name, :obj_or_widget, :editing_option
158
158
  end
159
159
  end
160
160
 
161
- def allowed_values
161
+ def valid_values
162
162
  MultiJson.encode(obj_or_widget.attribute_definitions[field_name].try(:values) || [])
163
163
  end
164
164
 
@@ -70,8 +70,8 @@ module Scrivito
70
70
 
71
71
  def self.upload_future_binary(future_binary, obj_id)
72
72
  if future_binary.id_to_copy
73
- id = normalize_path_component(future_binary.id_to_copy)
74
- put("blobs/#{id}/copy", future_binary.to_h.merge(destination_obj_id: obj_id))
73
+ copy_binary(normalize_path_component(future_binary.id_to_copy),
74
+ future_binary.to_h.merge(destination_obj_id: obj_id))
75
75
  else
76
76
  permission = get('blobs/upload_permission')
77
77
  upload = upload_file(future_binary.file_to_upload, future_binary.content_type, permission)
@@ -83,6 +83,10 @@ module Scrivito
83
83
  put('blobs/activate_upload', params)
84
84
  end
85
85
 
86
+ def self.copy_binary(id, params)
87
+ put("blobs/#{id}/copy", params)
88
+ end
89
+
86
90
  def self.normalize_path_component(component)
87
91
  Addressable::URI.normalize_component(component,
88
92
  Addressable::URI::CharacterClasses::UNRESERVED)
@@ -135,7 +139,7 @@ module Scrivito
135
139
  response = retry_once_on_network_error(method, timer) do
136
140
  CmsRestApi::RateLimit.retry_on_rate_limit(timer) do
137
141
  request_timeout = [timer.remaining_time, MAX_REQUEST_TIME].min
138
- connection_manager.request(request, request_timeout)
142
+ ConnectionManager.request(request, timeout: request_timeout)
139
143
  end
140
144
  end
141
145
 
@@ -189,7 +193,8 @@ module Scrivito
189
193
  upload_io = UploadIO.new(open_file, content_type, File.basename(file))
190
194
  params = upload_permission['fields'].merge('file' => upload_io)
191
195
  request = Net::HTTP::Post::Multipart.new(uri.path, params)
192
- response = ConnectionManager.request(uri, request)
196
+ response = ConnectionManager.request(request, uri: uri)
197
+
193
198
  if response.code.starts_with?('2')
194
199
  upload_permission['blob']
195
200
  else
@@ -231,10 +236,6 @@ module Scrivito
231
236
  "/#{Configuration.endpoint_uri.path}/#{path}".squeeze('/')
232
237
  end
233
238
 
234
- def connection_manager
235
- ConnectionManager.instance
236
- end
237
-
238
239
  def build_timer(options={})
239
240
  CmsRestApi::RequestTimer.new(options.fetch(:timeout, DEFAULT_TIMEOUT))
240
241
  end
@@ -77,7 +77,7 @@ class CmsRouting < Struct.new(:request, :context, :scrivito_engine, :image_optio
77
77
 
78
78
  def path_or_url_for_objs(obj, path_or_url, options)
79
79
  permalink = obj.permalink
80
- if permalink && route_defined?(:permalink)
80
+ if permalink && route_defined?(:permalink) && permalink.split('/').first != 'scrivito'
81
81
  use_route(:permalink, path_or_url, options.merge(:permalink => permalink))
82
82
  elsif homepage?(obj) && route_defined?(:homepage)
83
83
  use_route(:homepage, path_or_url, options)
@@ -297,11 +297,22 @@ Please use the new scrivito_route api to replicate the legacy routes:
297
297
 
298
298
  attr_reader :default_image_transformation
299
299
 
300
- # Configure a callback to be invoked when the Scrivito SDK delivers the homepage.
301
- # The given callback will receive the rack env
302
- # and must return an {BasicObj Obj} to be used as the homepage.
303
- # If no callback is configured, {BasicObj.root Obj.root} will be used as the default.
304
300
  # @api public
301
+ #
302
+ # A callback that can be provided for determining the CMS object to be used when visiting
303
+ # the homepage. See {Scrivito::RoutingExtensions#scrivito_route scrivito_route} for
304
+ # details on how to define routes. The callback is called once per request and receives
305
+ # the rack environment as its only parameter. By default, the CMS object at the root
306
+ # path (+/+) is used as the homepage.
307
+ #
308
+ # @yield Rack environment of the current request
309
+ #
310
+ # @example
311
+ # Scrivito.configure do |config|
312
+ # config.choose_homepage do |env|
313
+ # Obj.root # Replace with code to set the homepage
314
+ # end
315
+ # end
305
316
  def choose_homepage(&block)
306
317
  self.choose_homepage_callback = block
307
318
  end
@@ -1,3 +1,5 @@
1
+ require 'connection_pool'
2
+
1
3
  module Scrivito
2
4
  class ConnectionManager
3
5
  DEFAULT_TIMEOUT = 10.freeze
@@ -5,22 +7,15 @@ module Scrivito
5
7
  attr_reader :uri
6
8
 
7
9
  class << self
8
- def instance
9
- @instance ||= new(Configuration.endpoint_uri)
10
- end
11
-
12
- # For test purpose only.
13
- def reset_instance!
14
- @instance = nil
15
- end
16
-
17
- def request(uri, request, timeout = nil)
18
- instance_for(uri).request(request, timeout)
10
+ def request(request, timeout: nil, uri: nil)
11
+ connection_pool_for(uri || Configuration.endpoint_uri).with do |connection|
12
+ connection.request(request, timeout)
13
+ end
19
14
  end
20
15
 
21
16
  # For test purpose only.
22
17
  def clear_cache!
23
- @instances = nil
18
+ @connection_pools = nil
24
19
  @cert_store = nil
25
20
  end
26
21
 
@@ -33,15 +28,17 @@ module Scrivito
33
28
 
34
29
  private
35
30
 
36
- def instance_for(uri)
31
+ def connection_pool_for(uri)
37
32
  endpoint_url = "#{uri.scheme}://#{uri.host}:#{uri.port}"
38
- instances.fetch(endpoint_url) do
39
- instances[endpoint_url] = new(URI.parse(endpoint_url))
33
+ connection_pools.fetch(endpoint_url) do
34
+ connection_pools[endpoint_url] = ConnectionPool.new(size: 100, timeout: 0) do
35
+ new(URI.parse(endpoint_url))
36
+ end
40
37
  end
41
38
  end
42
39
 
43
- def instances
44
- @instances ||= {}
40
+ def connection_pools
41
+ @connection_pools ||= {}
45
42
  end
46
43
  end
47
44
 
@@ -53,12 +50,16 @@ module Scrivito
53
50
  request['User-Agent'] = user_agent
54
51
  ensure_started(timeout)
55
52
 
56
- begin
57
- connection.request(request)
58
- rescue => e
59
- ensure_finished
60
- raise NetworkError.from_socket_error(e)
61
- end
53
+ # This should never happen!
54
+ raise InternalError, 'Connection is already in use!' if @in_use
55
+
56
+ @in_use = true
57
+ connection.request(request)
58
+ rescue => e
59
+ ensure_finished
60
+ raise NetworkError.from_socket_error(e)
61
+ ensure
62
+ @in_use = false
62
63
  end
63
64
 
64
65
  # for testing purposes
@@ -66,6 +67,11 @@ module Scrivito
66
67
  @connect_count || 0
67
68
  end
68
69
 
70
+ # For test purpose only.
71
+ def in_use?
72
+ !!@in_use
73
+ end
74
+
69
75
  private
70
76
 
71
77
  attr_accessor :connection
@@ -4,10 +4,13 @@ module Scrivito
4
4
  # @api public
5
5
  #
6
6
  class ModelLibrary
7
- attr_reader :custom_pages, :custom_widgets, :custom_paths
7
+ attr_reader :custom_pages, :custom_widgets, :custom_objs, :custom_paths
8
8
 
9
9
  def initialize
10
- @custom_pages, @custom_widgets, @custom_paths = [], [], []
10
+ @custom_pages = []
11
+ @custom_widgets = []
12
+ @custom_objs = []
13
+ @custom_paths = []
11
14
  end
12
15
 
13
16
  #
@@ -17,13 +20,14 @@ class ModelLibrary
17
20
  # @see Scrivito.models
18
21
  #
19
22
  def clear_cache
20
- @pages = nil
23
+ @pages = nil
21
24
  @widgets = nil
22
- @paths = nil
25
+ @objs = nil
26
+ @paths = nil
23
27
  end
24
28
 
25
29
  #
26
- # Configures which models Scrivito assumes as pages and widgets.
30
+ # Configures which models Scrivito assumes as pages, widgets and objs.
27
31
  #
28
32
  # @api public
29
33
  # @see Scrivito.models
@@ -54,6 +58,25 @@ class ModelLibrary
54
58
  @widgets ||= load_models('widget', Scrivito::BasicWidget)
55
59
  end
56
60
 
61
+ #
62
+ # Lists available CMS object models.
63
+ #
64
+ # @api public
65
+ # @see Scrivito.models
66
+ # @return [Scrivito::ClassCollection] available CMS object classes
67
+ #
68
+ def objs
69
+ @objs ||= load_obj_models
70
+ end
71
+
72
+ def load_obj_models
73
+ base_class = Scrivito::BasicObj
74
+ model_classes = load_models_from_paths('obj', base_class) +
75
+ load_custom_models('obj', base_class) +
76
+ load_custom_models('page', base_class)
77
+ ClassCollection.new(model_classes)
78
+ end
79
+
57
80
  #
58
81
  # Lists available paths to scan for models.
59
82
  #
@@ -69,7 +92,7 @@ class ModelLibrary
69
92
 
70
93
  def load_models(type, base_class)
71
94
  model_classes = load_models_from_paths(type, base_class) + load_custom_models(type, base_class)
72
- ClassCollection.new(model_classes.compact)
95
+ ClassCollection.new(model_classes)
73
96
  end
74
97
 
75
98
  def load_models_from_paths(type, base_class)
@@ -78,20 +101,25 @@ class ModelLibrary
78
101
 
79
102
  def load_models_from_path(type, path, base_class)
80
103
  candidates_from_path(type, path).map do |file_path|
81
- load_model(file_path.gsub(path, '').gsub('.rb', '').classify, base_class)
104
+ load_model(file_path.gsub(path, '').gsub('.rb', '').camelize, base_class)
82
105
  end
83
106
  end
84
107
 
85
108
  def candidates_from_path(type, path)
86
- result = Dir["#{path}/**/*_#{type}.rb"]
87
- result += Dir["#{path}/**/page.rb"] if type == 'page'
88
- result
109
+ Dir["#{path}/**/*.rb"].select do |file_path|
110
+ case type
111
+ when 'page' then file_path.ends_with?('page.rb')
112
+ when 'widget' then file_path.ends_with?('_widget.rb')
113
+ else true
114
+ end
115
+ end
89
116
  end
90
117
 
91
118
  def load_model(class_name, base_class)
92
119
  model_class = class_name.constantize
93
120
  model_class if model_class.ancestors.include?(base_class)
94
- rescue NameError
121
+ rescue LoadError
122
+ # Ignore files with invalid models, e.g. empty files.
95
123
  end
96
124
 
97
125
  def load_custom_models(type, base_class)
@@ -107,6 +135,10 @@ class ModelLibrary
107
135
  end
108
136
 
109
137
  class DSL < Struct.new(:model_library)
138
+ def obj(*names)
139
+ model_library.custom_objs.push(*names)
140
+ end
141
+
110
142
  def page(*names)
111
143
  model_library.custom_pages.push(*names)
112
144
  end
@@ -137,7 +137,7 @@ module Scrivito
137
137
  # Accepts the name of an "obj_by" view, a list of keys.
138
138
  # Returns a list of lists of Objs: a list of Objs for each given key.
139
139
  def find_by_including_deleted(view, keys)
140
- result = CmsBackend.instance.find_obj_data_by(
140
+ result = CmsBackend.find_obj_data_by(
141
141
  workspace.revision,
142
142
  view,
143
143
  keys)
@@ -54,25 +54,7 @@ module Scrivito
54
54
 
55
55
  def parse_binary_params(params)
56
56
  return unless params
57
-
58
- if params[:copy]
59
- parse_copy_binary_params(params[:copy])
60
- else
61
- UploadedBinary.new(params)
62
- end
63
- end
64
-
65
- def parse_copy_binary_params(params)
66
- obj = Obj.find(params[:obj_id])
67
-
68
- if widget_id = params[:widget_id]
69
- widget = obj.widgets[widget_id]
70
- raise_widget_not_found_error(widget_id) unless widget
71
- end
72
-
73
- if binary = (widget || obj)[params[:attribute_name]]
74
- binary.copy(params.slice(:filename, :content_type).compact)
75
- end
57
+ UploadedBinary.new(params)
76
58
  end
77
59
 
78
60
  def raise_widget_not_found_error(widget_id)
@@ -7,7 +7,7 @@ class ObjSearchEnumerator
7
7
 
8
8
  def call(query, continuation=nil, fetched_ids=[])
9
9
  query['continuation'] = continuation if continuation
10
- response = CmsBackend.instance.search_objs(workspace, query)
10
+ response = CmsBackend.search_objs(workspace, query)
11
11
 
12
12
  ObjSearchEnumerator::Batch.new(
13
13
  build_objs(response),
@@ -349,7 +349,7 @@ module Scrivito
349
349
  }
350
350
  end
351
351
 
352
- @size ||= CmsBackend.instance.search_objs(workspace, size_query)['total'].to_i
352
+ @size ||= CmsBackend.search_objs(workspace, size_query)['total'].to_i
353
353
  end
354
354
 
355
355
  # Loads a single batch of search results from the backend.
@@ -1,19 +1,22 @@
1
1
  module Scrivito
2
2
 
3
- class UiConfig < Struct.new(:editing_context, :resource, :return_to, :app_extension_tags)
3
+ class UiConfig < Struct.new(:editing_context, :resource, :return_to, :app_extension_tags,
4
+ :obj_models, :widget_models)
4
5
  def initialize(**named_params)
5
6
  named_params.each { |key, value| self[key] = value }
6
7
  end
7
8
 
8
9
  def to_json
9
10
  {
11
+ app_extension_tags: app_extension_tags,
10
12
  editing_context: editing_context_config,
11
13
  i18n: i18n_config,
12
14
  is_development_mode: Rails.env.development?,
13
15
  resource_dialog: resource_dialog_config,
14
16
  user: user_config,
15
17
  user_permissions: user_permissions_config,
16
- app_extension_tags: app_extension_tags,
18
+ obj_class: obj_class_config,
19
+ widget_class: widget_class_config,
17
20
  }.to_json
18
21
  end
19
22
 
@@ -46,6 +49,14 @@ class UiConfig < Struct.new(:editing_context, :resource, :return_to, :app_extens
46
49
  {locale: Scrivito::Configuration.ui_locale || I18n.locale}
47
50
  end
48
51
 
52
+ def obj_class_config
53
+ obj_models.map(&:as_json)
54
+ end
55
+
56
+ def widget_class_config
57
+ widget_models.map(&:as_json)
58
+ end
59
+
49
60
  def resource_dialog_config
50
61
  return {} unless resource
51
62
  {