scrivito_sdk 1.1.1 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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
  {