scrivito_sdk 0.66.0 → 0.70.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/scrivito/blobs_controller.rb +5 -0
- data/app/controllers/scrivito/objs_controller.rb +2 -1
- data/app/controllers/scrivito/ui_controller.rb +33 -3
- data/app/helpers/scrivito_helper.rb +14 -20
- data/app/views/scrivito/objs/update.json.jbuilder +1 -1
- data/app/views/scrivito/ui/index.html.erb +1 -1
- data/app/views/scrivito/webservice/_workspace.json.jbuilder +2 -1
- data/config/ca-bundle.crt +1 -1
- data/config/precedence_routes.rb +3 -2
- data/lib/assets/javascripts/scrivito.js +46 -0
- data/lib/assets/javascripts/scrivito_ui.js +931 -501
- data/lib/assets/stylesheets/scrivito.css +1 -0
- data/lib/assets/stylesheets/scrivito_ui.css +1 -1
- data/lib/generators/scrivito/install/templates/app/views/page/index.html.erb +3 -3
- data/lib/generators/scrivito/page/page_generator.rb +3 -0
- data/lib/generators/scrivito/page/templates/model.erb +3 -0
- data/lib/generators/scrivito/widget/templates/model.erb +3 -0
- data/lib/generators/scrivito/widget/widget_generator.rb +3 -0
- data/lib/scrivito/attribute_content.rb +93 -60
- data/lib/scrivito/attribute_definition.rb +3 -3
- data/lib/scrivito/attribute_serializer.rb +2 -2
- data/lib/scrivito/backend/obj_data_cache.rb +22 -9
- data/lib/scrivito/basic_obj.rb +238 -130
- data/lib/scrivito/basic_widget.rb +32 -20
- data/lib/scrivito/binary.rb +74 -45
- data/lib/scrivito/binary_routing.rb +52 -0
- data/lib/scrivito/cache_middleware.rb +0 -5
- data/lib/scrivito/client_attribute_serializer.rb +134 -0
- data/lib/scrivito/cms_backend.rb +51 -33
- data/lib/scrivito/cms_data_cache.rb +1 -0
- data/lib/scrivito/cms_dispatch_controller.rb +1 -1
- data/lib/scrivito/cms_env.rb +1 -11
- data/lib/scrivito/cms_field_tag.rb +10 -7
- data/lib/scrivito/cms_rest_api/rate_limit.rb +5 -5
- data/lib/scrivito/cms_rest_api/request_timer.rb +27 -0
- data/lib/scrivito/cms_rest_api/widget_extractor.rb +8 -6
- data/lib/scrivito/cms_rest_api.rb +107 -54
- data/lib/scrivito/cms_routing.rb +13 -25
- data/lib/scrivito/configuration.rb +5 -2
- data/lib/scrivito/controller_actions.rb +68 -7
- data/lib/scrivito/controller_runtime.rb +8 -0
- data/lib/scrivito/date_attribute.rb +8 -0
- data/lib/scrivito/errors.rb +6 -3
- data/lib/scrivito/generator_helper.rb +13 -0
- data/lib/scrivito/image_tag.rb +24 -30
- data/lib/scrivito/layout_tags.rb +12 -6
- data/lib/scrivito/link.rb +46 -30
- data/lib/scrivito/log_subscriber.rb +15 -0
- data/lib/scrivito/membership.rb +3 -3
- data/lib/scrivito/membership_collection.rb +10 -10
- data/lib/scrivito/meta_data_collection.rb +22 -0
- data/lib/scrivito/model_library.rb +7 -1
- data/lib/scrivito/obj_collection.rb +18 -16
- data/lib/scrivito/obj_params_parser.rb +1 -1
- data/lib/scrivito/obj_search_enumerator.rb +35 -35
- data/lib/scrivito/page_config.rb +55 -0
- data/lib/scrivito/request_homepage.rb +23 -0
- data/lib/scrivito/routing_helper.rb +8 -8
- data/lib/scrivito/sdk_engine.rb +2 -3
- data/lib/scrivito/ui_config.rb +85 -0
- data/lib/scrivito/user.rb +30 -23
- data/lib/scrivito/user_definition.rb +48 -47
- data/lib/scrivito/widget_tag.rb +11 -0
- data/lib/scrivito/workspace.rb +93 -35
- data/lib/scrivito/workspace_selection_middleware.rb +8 -1
- data/lib/scrivito_sdk.rb +24 -24
- metadata +24 -33
- data/lib/assets/javascripts/scrivito_sdk.js +0 -57
- data/lib/assets/stylesheets/scrivito_sdk.css +0 -1
- data/lib/scrivito/client_config.rb +0 -113
- data/lib/scrivito/editing_context_helper.rb +0 -19
- data/lib/scrivito/named_link.rb +0 -39
data/lib/scrivito/basic_obj.rb
CHANGED
@@ -4,11 +4,19 @@ require 'active_model/naming'
|
|
4
4
|
|
5
5
|
module Scrivito
|
6
6
|
#
|
7
|
-
# The abstract base class for
|
7
|
+
# The abstract base class for CMS objects.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# A CMS object is a collection of properties and their values, as defined
|
10
|
+
# by its object class. These properties can be accessed in views, either
|
11
|
+
# directly as the object itself is rendered, or indirectly when other objects
|
12
|
+
# are rendered. The description of an image, for example, can be retrieved
|
13
|
+
# from within any view that requires it, e.g. a page on which the image is
|
14
|
+
# displayed.
|
15
|
+
#
|
16
|
+
# @note Please do not use {Scrivito::BasicObj} directly
|
10
17
|
# as it is intended as an abstract class.
|
11
18
|
# Always use {Obj} or a subclass of {Obj}.
|
19
|
+
# @see http://scrivito.com/objects-widgets-classes CMS objects, widgets, and classes
|
12
20
|
# @api public
|
13
21
|
#
|
14
22
|
class BasicObj
|
@@ -59,27 +67,27 @@ module Scrivito
|
|
59
67
|
#
|
60
68
|
# @api public
|
61
69
|
#
|
62
|
-
# This allows you to set the different attributes
|
63
|
-
#
|
64
|
-
#
|
70
|
+
# This allows you to set the different attributes of an Obj by providing a hash containing the
|
71
|
+
# attribute names as keys and the corresponding values you want to set. The defaults set via
|
72
|
+
# {Scrivito::AttributeContent::ClassMethods#default_for Obj.default_for} are taken into account.
|
65
73
|
#
|
66
|
-
# @param [Hash] attributes
|
67
|
-
# @param [Hash] context in which the object
|
74
|
+
# @param [Hash] attributes of the new obj
|
75
|
+
# @param [Hash] context in which the object is created
|
68
76
|
# @option context [Scrivito::User] :scrivito_user current visitor
|
69
77
|
# @return [Obj] the newly created {Scrivito::BasicObj Obj}
|
70
78
|
#
|
71
79
|
# @see Scrivito::AttributeContent::ClassMethods#default_for
|
72
80
|
#
|
73
|
-
# @example
|
81
|
+
# @example Provide reference lists as an Array of {Scrivito::BasicObj Obj}.
|
74
82
|
# Obj.create(:reference_list => [other_obj])
|
75
83
|
#
|
76
|
-
# @example Passing an {Scrivito::BasicObj Obj} allows you to set a reference
|
84
|
+
# @example Passing an {Scrivito::BasicObj Obj} allows you to set a reference.
|
77
85
|
# Obj.create(:reference => other_obj)
|
78
86
|
#
|
79
|
-
# @example
|
87
|
+
# @example You can upload files by passing a Ruby File object.
|
80
88
|
# Obj.create(:blob => File.new("image.png"))
|
81
89
|
#
|
82
|
-
# @example
|
90
|
+
# @example A link list can be set as an Array of {Link Links}.
|
83
91
|
# Obj.create(:link_list => [
|
84
92
|
# # external link
|
85
93
|
# Link.new(:url => "http://www.example.com", :title => "Example"),
|
@@ -89,34 +97,35 @@ module Scrivito
|
|
89
97
|
#
|
90
98
|
# @example Passing a {Link Link} allows you to set a link.
|
91
99
|
# Obj.create(
|
92
|
-
# external_link: Link.new(url: 'http://www.example.com', title: 'Example')
|
100
|
+
# external_link: Link.new(url: 'http://www.example.com', title: 'Example'),
|
93
101
|
# internal_link: Link.new(obj: other_obj, title: 'Other Obj')
|
94
102
|
# )
|
95
103
|
#
|
96
|
-
# @example
|
104
|
+
# @example Date attributes accept Time, Date and their subclasses (DateTime, for example).
|
97
105
|
# Obj.create(:date => Time.new)
|
98
106
|
# Obj.create(:date => Date.now)
|
99
107
|
#
|
100
|
-
# @example String, html and enum can be set by passing a {String} value
|
108
|
+
# @example String, html and enum attributes can be set by passing a {String} value.
|
101
109
|
# Obj.create(:title => "My Title")
|
102
110
|
#
|
103
|
-
# @example
|
111
|
+
# @example Multienum attributes can be set using an Array of {String Strings}.
|
104
112
|
# Obj.create(:tags => ["ruby", "rails"])
|
105
113
|
#
|
106
|
-
# @example Simply pass an Array of {Scrivito::BasicWidget Widgets} to
|
114
|
+
# @example Simply pass an Array of {Scrivito::BasicWidget Widgets} to populate a widget field. See {Scrivito::BasicWidget#copy Widget#copy} on how to copy a widget.
|
107
115
|
# # Add new widgets
|
108
116
|
# Obj.create(:widgets => [Widget.new(_obj_class: 'TitleWidget', title: 'My Title')])
|
109
117
|
#
|
110
|
-
# # Add a widget
|
118
|
+
# # Add a copy of a widget
|
111
119
|
# Obj.create(:widgets => [another_obj.widgets.first.copy])
|
112
120
|
#
|
113
|
-
# #
|
121
|
+
# # Change a widget field
|
114
122
|
# obj.update(:widgets => [obj.widgets.first])
|
115
123
|
#
|
116
124
|
# # Clear a widget field
|
117
125
|
# obj.update(:widgets => [])
|
118
126
|
#
|
119
127
|
def self.create(attributes = {}, context = {})
|
128
|
+
attributes = with_default_id_attribute(attributes)
|
120
129
|
if obj_class = extract_obj_class_from_attributes(attributes)
|
121
130
|
obj_class.create(attributes, context)
|
122
131
|
else
|
@@ -131,8 +140,8 @@ module Scrivito
|
|
131
140
|
end
|
132
141
|
|
133
142
|
# Create a new {Scrivito::BasicObj Obj} instance with the given values and attributes.
|
134
|
-
# Normally this method should not be used.
|
135
|
-
# Instead
|
143
|
+
# Normally, this method should not be used.
|
144
|
+
# Instead, CMS objects should be retrieved from the CMS database.
|
136
145
|
def initialize(attributes = {})
|
137
146
|
update_data(ObjDataFromHash.new(attributes))
|
138
147
|
end
|
@@ -153,8 +162,10 @@ module Scrivito
|
|
153
162
|
|
154
163
|
### FINDERS ####################
|
155
164
|
|
156
|
-
# Find
|
157
|
-
# If the parameter is an Array
|
165
|
+
# Find an {Scrivito::BasicObj Obj} by its id.
|
166
|
+
# If the parameter is an Array of ids, the list of corresponding objects is returned.
|
167
|
+
# @example Find several CMS objects at once:
|
168
|
+
# Obj.find(['id1', 'id2'])
|
158
169
|
# @param [String, Integer, Array<String, Integer>]id_or_list
|
159
170
|
# @return [Obj, Array<Obj>]
|
160
171
|
# @api public
|
@@ -166,8 +177,8 @@ module Scrivito
|
|
166
177
|
Workspace.current.objs.find_by_id(id)
|
167
178
|
end
|
168
179
|
|
169
|
-
# Find
|
170
|
-
# If the parameter is an Array containing ids, return a list of corresponding
|
180
|
+
# Find an {Scrivito::BasicObj Obj} by its id.
|
181
|
+
# If the parameter is an Array containing ids, return a list of corresponding objects.
|
171
182
|
# The results include deleted objects as well.
|
172
183
|
# @param [String, Integer, Array<String, Integer>]id_or_list
|
173
184
|
# @return [Obj, Array<Obj>]
|
@@ -176,17 +187,26 @@ module Scrivito
|
|
176
187
|
Workspace.current.objs.find_including_deleted(id_or_list)
|
177
188
|
end
|
178
189
|
|
179
|
-
# Returns
|
190
|
+
# Returns an {ObjSearchEnumerator} with the given initial subquery consisting of the four arguments.
|
180
191
|
#
|
181
192
|
# Note that +field+ and +value+ can also be arrays for searching several fields or searching for several values.
|
182
193
|
#
|
183
|
-
# @note If invoked on a subclass of Obj, the result will be restricted to instances of
|
194
|
+
# @note If invoked on a subclass of Obj, the result will be restricted to instances of this subclass.
|
184
195
|
#
|
185
196
|
# {ObjSearchEnumerator}s can be chained using one of the chainable methods
|
186
197
|
# (e.g. {ObjSearchEnumerator#and} and {ObjSearchEnumerator#and_not}).
|
187
198
|
#
|
188
|
-
# @example Look for
|
199
|
+
# @example Look for objects containing "Lorem", boosting headline matches:
|
200
|
+
# Obj.where(:*, :contains, 'Lorem', headline: 2).to_a
|
201
|
+
#
|
202
|
+
# @example Look for the first 10 objects whose object class is "Pressrelease" and whose title contains "quarterly":
|
189
203
|
# Obj.where(:_obj_class, :equals, 'Pressrelease').and(:title, :contains, 'quarterly').take(10)
|
204
|
+
#
|
205
|
+
# @example Look for all objects whose class is "Item". The path should start with a defined location. Furthermore, select only items of a particular category:
|
206
|
+
# Obj.where(:_obj_class, :equals, 'Item').and(:_path, :starts_with, '/en/items/').select do |item|
|
207
|
+
# item.categories.include?(category)
|
208
|
+
# end
|
209
|
+
#
|
190
210
|
# @param [Symbol, String, Array<Symbol, String>] field See {ObjSearchEnumerator#and} for details
|
191
211
|
# @param [Symbol, String] operator See {ObjSearchEnumerator#and} for details
|
192
212
|
# @param [String, Array<String>] value See {ObjSearchEnumerator#and} for details
|
@@ -204,8 +224,8 @@ module Scrivito
|
|
204
224
|
end
|
205
225
|
end
|
206
226
|
|
207
|
-
# Returns
|
208
|
-
# If invoked on a subclass of Obj, the result
|
227
|
+
# Returns an {ObjSearchEnumerator} of all {Scrivito::BasicObj Obj}s.
|
228
|
+
# If invoked on a subclass of Obj, the result is restricted to instances of this subclass.
|
209
229
|
# @return [ObjSearchEnumerator]
|
210
230
|
# @raise [ScrivitoError] if called directly on +BasicObj+. Use +Obj.all+ instead.
|
211
231
|
# @api public
|
@@ -218,8 +238,8 @@ module Scrivito
|
|
218
238
|
end
|
219
239
|
end
|
220
240
|
|
221
|
-
# Returns
|
222
|
-
# @param [String] obj_class name of the
|
241
|
+
# Returns an {ObjSearchEnumerator} of all CMS objects with the given +obj_class+.
|
242
|
+
# @param [String] obj_class name of the object class.
|
223
243
|
# @return [ObjSearchEnumerator]
|
224
244
|
# @api public
|
225
245
|
def self.find_all_by_obj_class(obj_class)
|
@@ -236,8 +256,8 @@ module Scrivito
|
|
236
256
|
end
|
237
257
|
|
238
258
|
# Find an {Scrivito::BasicObj Obj} with the given name.
|
239
|
-
# If several
|
240
|
-
# If no Obj with
|
259
|
+
# If several objects with the given name exist, an arbitrary one is chosen and returned.
|
260
|
+
# If no Obj with this name exists, +nil+ is returned.
|
241
261
|
# @param [String] name Name of the {Scrivito::BasicObj Obj}.
|
242
262
|
# @return [Obj]
|
243
263
|
# @api public
|
@@ -245,7 +265,7 @@ module Scrivito
|
|
245
265
|
where(:_name, :equals, name).batch_size(1).first
|
246
266
|
end
|
247
267
|
|
248
|
-
# Returns
|
268
|
+
# Returns an {ObjSearchEnumerator} of all CMS objects with the given name.
|
249
269
|
# @param [String] name Name of the {Scrivito::BasicObj Obj}.
|
250
270
|
# @return [ObjSearchEnumerator]
|
251
271
|
# @api public
|
@@ -253,8 +273,8 @@ module Scrivito
|
|
253
273
|
where(:_name, :equals, name)
|
254
274
|
end
|
255
275
|
|
256
|
-
# Returns the {Scrivito::BasicObj Obj} with the given permalink, or +nil+ if no
|
257
|
-
# exists.
|
276
|
+
# Returns the {Scrivito::BasicObj Obj} with the given permalink, or +nil+ if no
|
277
|
+
# matching Obj exists.
|
258
278
|
# @param [String] permalink The permalink of the {Scrivito::BasicObj Obj}.
|
259
279
|
# @return [Obj]
|
260
280
|
# @api public
|
@@ -262,7 +282,7 @@ module Scrivito
|
|
262
282
|
Workspace.current.objs.find_by_permalink(permalink)
|
263
283
|
end
|
264
284
|
|
265
|
-
# Returns the {Scrivito::BasicObj Obj} with the given permalink, or
|
285
|
+
# Returns the {Scrivito::BasicObj Obj} with the given permalink, or raises ResourceNotFound if
|
266
286
|
# no matching Obj exists.
|
267
287
|
# @param [String] permalink The permalink of the {Scrivito::BasicObj Obj}.
|
268
288
|
# @return [Obj]
|
@@ -272,19 +292,19 @@ module Scrivito
|
|
272
292
|
raise ResourceNotFound, "Could not find Obj with permalink '#{permalink}'"
|
273
293
|
end
|
274
294
|
|
275
|
-
# Hook method
|
276
|
-
# Override it to allow only
|
295
|
+
# Hook method that lets you control which page classes are made available for pages with the given path.
|
296
|
+
# Override it to allow only specific classes or none at all.
|
277
297
|
# Must return either +NilClass+, or +Array+.
|
278
298
|
#
|
279
299
|
# Be aware that the given argument is a parent path.
|
280
|
-
# E.g
|
300
|
+
# E.g., when creating a page whose path is +/products/shoes+, the argument must be +/products+.
|
281
301
|
# The given parent path can also be +NilClass+.
|
282
302
|
#
|
283
|
-
# If +NilClass+ is returned,
|
284
|
-
# By default +NilClass+ is returned.
|
303
|
+
# If +NilClass+ is returned, all page classes are made available.
|
304
|
+
# By default, +NilClass+ is returned.
|
285
305
|
#
|
286
|
-
# If +Array+ is returned,
|
287
|
-
#
|
306
|
+
# If an +Array+ is returned, it is expected to contain the available classes.
|
307
|
+
# The order of the classes is preserved.
|
288
308
|
#
|
289
309
|
# @param [String, NilClass] parent_path Path of the parent obj
|
290
310
|
# @return [NilClass, Array<Class>]
|
@@ -297,9 +317,9 @@ module Scrivito
|
|
297
317
|
Scrivito.models.pages.to_a
|
298
318
|
end
|
299
319
|
|
300
|
-
# Update the {Scrivito::BasicObj Obj}
|
320
|
+
# Update the {Scrivito::BasicObj Obj} using the attributes provided.
|
301
321
|
#
|
302
|
-
# For an overview of
|
322
|
+
# For an overview of the values you can set via this method, see the
|
303
323
|
# documentation of {Scrivito::BasicObj.create Obj.create}.
|
304
324
|
#
|
305
325
|
# Additionally, +update+ accepts a +_widget_pool+ hash in +attributes+ to modify widgets.
|
@@ -308,6 +328,20 @@ module Scrivito
|
|
308
328
|
#
|
309
329
|
# @api public
|
310
330
|
# @param [Hash] attributes
|
331
|
+
# @example Update the URL of a link:
|
332
|
+
# link = obj.my_link
|
333
|
+
# link.url = "http://www.example.com"
|
334
|
+
# obj.update(my_link: link)
|
335
|
+
#
|
336
|
+
# @example Update binary attributes:
|
337
|
+
# obj.update(blob: img_obj.binary)
|
338
|
+
# obj.update(thumbnail: File.new("/path/to/small.jpg"))
|
339
|
+
#
|
340
|
+
# @example Remove the first and the last widget from a widget field:
|
341
|
+
# obj.update(
|
342
|
+
# my_widget_field: obj[:my_widget_field][1..-2]
|
343
|
+
# )
|
344
|
+
#
|
311
345
|
# @example Move the +widget_to_move+ widget from the +left+ widget field of the +two_column_widget1+ widget to +left+ of +two_column_widget2+:
|
312
346
|
# obj.update(
|
313
347
|
# _widget_pool: {
|
@@ -317,7 +351,7 @@ module Scrivito
|
|
317
351
|
# headline: "Some widgets were moved!"
|
318
352
|
# )
|
319
353
|
#
|
320
|
-
# @example Move the +widget_to_move+ widget from the +right+ widget field of the +two_column_widget1+ widget to the top-level widget field
|
354
|
+
# @example Move the +widget_to_move+ widget from the +right+ widget field of the +two_column_widget1+ widget to the top-level +main_content+ widget field:
|
321
355
|
# obj.update(
|
322
356
|
# main_content: @obj.main_content + [widget_to_move],
|
323
357
|
# _widget_pool: {
|
@@ -334,7 +368,7 @@ module Scrivito
|
|
334
368
|
self
|
335
369
|
end
|
336
370
|
|
337
|
-
# Creates a copy of the
|
371
|
+
# Creates a copy of the {Scrivito::BasicObj Obj}.
|
338
372
|
# @api public
|
339
373
|
# @param [Hash] options
|
340
374
|
# @option options [String,Symbol] :_path (nil) the path of the copy.
|
@@ -342,16 +376,19 @@ module Scrivito
|
|
342
376
|
# @option options [String,Symbol] :_permalink (nil) the permalink of the copy.
|
343
377
|
# @raise [ArgumentError] if +options+ includes invalid keys.
|
344
378
|
# @return [Obj] the created copy
|
345
|
-
# @example Copy a blog post
|
379
|
+
# @example Copy a blog post:
|
346
380
|
# blog_post = Obj.find_by_path('/blog/first_post')
|
347
381
|
# blog_post.copy(_path: '/blog/second_post')
|
348
382
|
def copy(options={})
|
349
383
|
options = options.stringify_keys.assert_valid_keys('_path', '_id', '_permalink')
|
350
|
-
|
384
|
+
attributes_for_copy = self.class.with_default_id_attribute(copyable_attributes)
|
385
|
+
attributes_for_copy = copy_binaries(attributes_for_copy)
|
386
|
+
|
387
|
+
json = workspace.api_request(:post, '/objs', obj: attributes_for_copy.merge(options))
|
351
388
|
self.class.find(json['_id'])
|
352
389
|
end
|
353
390
|
|
354
|
-
# Destroys the {Scrivito::BasicObj Obj} in the current {Workspace}
|
391
|
+
# Destroys the {Scrivito::BasicObj Obj} in the current {Workspace}.
|
355
392
|
# @api public
|
356
393
|
def destroy
|
357
394
|
if children.any?
|
@@ -364,8 +401,8 @@ module Scrivito
|
|
364
401
|
id
|
365
402
|
end
|
366
403
|
|
367
|
-
#
|
368
|
-
#
|
404
|
+
# Returns the {Scrivito::BasicObj Obj} that is the parent of this Obj.
|
405
|
+
# Returns +nil+ for the root Obj.
|
369
406
|
# @api public
|
370
407
|
def parent
|
371
408
|
if child_path?
|
@@ -373,7 +410,7 @@ module Scrivito
|
|
373
410
|
end
|
374
411
|
end
|
375
412
|
|
376
|
-
# Returns an Array of all the ancestor objects, starting at the root and ending at this object
|
413
|
+
# Returns an Array of all the ancestor objects, starting at the root and ending at the parent of this object.
|
377
414
|
# @return [Array<Obj>]
|
378
415
|
# @api public
|
379
416
|
def ancestors
|
@@ -386,7 +423,7 @@ module Scrivito
|
|
386
423
|
Workspace.current.objs.find_by_paths(ancestor_paths)
|
387
424
|
end
|
388
425
|
|
389
|
-
#
|
426
|
+
# Returns a list of all child {Scrivito::BasicObj Obj}s.
|
390
427
|
# @return [Array<Obj>]
|
391
428
|
# @api public
|
392
429
|
def children
|
@@ -397,13 +434,13 @@ module Scrivito
|
|
397
434
|
|
398
435
|
### ATTRIBUTES #################
|
399
436
|
|
400
|
-
#
|
437
|
+
# Returns the path of the {Scrivito::BasicObj Obj} as a String.
|
401
438
|
# @api public
|
402
439
|
def path
|
403
440
|
read_attribute('_path')
|
404
441
|
end
|
405
442
|
|
406
|
-
#
|
443
|
+
# Returns the name of the {Scrivito::BasicObj Obj}. The name is the last component of a path.
|
407
444
|
# @api public
|
408
445
|
def name
|
409
446
|
if child_path?
|
@@ -413,7 +450,7 @@ module Scrivito
|
|
413
450
|
end
|
414
451
|
end
|
415
452
|
|
416
|
-
# Returns the root {Scrivito::BasicObj Obj},
|
453
|
+
# Returns the root {Scrivito::BasicObj Obj}, the object whose path is "/".
|
417
454
|
# @return [Obj]
|
418
455
|
# @api public
|
419
456
|
def self.root
|
@@ -423,27 +460,19 @@ module Scrivito
|
|
423
460
|
'Try "bundle exec rake scrivito:migrate scrivito:migrate:publish".'
|
424
461
|
end
|
425
462
|
|
426
|
-
# Returns the homepage obj. This can be overridden in your application's +Obj+.
|
427
|
-
# Use {#homepage?} to check if an obj is the homepage.
|
428
|
-
# @return [Obj]
|
429
|
-
# @api public
|
430
|
-
def self.homepage
|
431
|
-
root
|
432
|
-
end
|
433
|
-
|
434
463
|
def self.generate_widget_pool_id
|
435
464
|
SecureRandom.hex(4)
|
436
465
|
end
|
437
466
|
|
438
|
-
#
|
467
|
+
# Returns the permalink of the {Scrivito::BasicObj Obj}.
|
439
468
|
# @api public
|
440
469
|
def permalink
|
441
470
|
read_attribute('_permalink')
|
442
471
|
end
|
443
472
|
|
444
|
-
# This method determines the controller
|
445
|
-
# By default a controller matching the
|
446
|
-
# If the controller does not exist, the CmsController
|
473
|
+
# This method determines the controller to be invoked when the +Obj+ is requested.
|
474
|
+
# By default, a controller matching the obj_class of the Obj is used.
|
475
|
+
# If the controller does not exist, the CmsController is used as a fallback.
|
447
476
|
# Override this method to force a different controller to be used.
|
448
477
|
# @return [String]
|
449
478
|
# @api public
|
@@ -451,7 +480,7 @@ module Scrivito
|
|
451
480
|
obj_class_name
|
452
481
|
end
|
453
482
|
|
454
|
-
# This method determines the action
|
483
|
+
# This method determines the action to be invoked when the +Obj+ is requested.
|
455
484
|
# The default action is 'index'.
|
456
485
|
# Override this method to force a different action to be used.
|
457
486
|
# @return [String]
|
@@ -460,15 +489,9 @@ module Scrivito
|
|
460
489
|
"index"
|
461
490
|
end
|
462
491
|
|
463
|
-
# Returns true if the current obj is the {.homepage} obj.
|
464
|
-
# @api public
|
465
|
-
def homepage?
|
466
|
-
self == self.class.homepage
|
467
|
-
end
|
468
|
-
|
469
492
|
# This method is used to calculate a part of a URL of this Obj.
|
470
493
|
#
|
471
|
-
# The routing schema: <code><em><obj.
|
494
|
+
# The routing schema: <code><em><obj.slug></em>-<em><obj.id></em></code>
|
472
495
|
#
|
473
496
|
# The default is {http://apidock.com/rails/ActiveSupport/Inflector/parameterize parameterize}
|
474
497
|
# on +obj.title+.
|
@@ -481,8 +504,8 @@ module Scrivito
|
|
481
504
|
end
|
482
505
|
|
483
506
|
#
|
484
|
-
# This method determines the description
|
485
|
-
#
|
507
|
+
# This method determines the description shown in the UI.
|
508
|
+
# It defaults to {Scrivito::BasicObj#display_title}. It can be overridden by a custom value.
|
486
509
|
#
|
487
510
|
# @api public
|
488
511
|
#
|
@@ -505,7 +528,7 @@ module Scrivito
|
|
505
528
|
|
506
529
|
# The alt description of an +Obj+ used for {ScrivitoHelper#scrivito_image_tag}.
|
507
530
|
#
|
508
|
-
# By default this method returns the +title+ of
|
531
|
+
# By default, this method returns the +title+ of the +Obj+.
|
509
532
|
#
|
510
533
|
# You can customize this part by overriding {#alt_description}.
|
511
534
|
#
|
@@ -521,11 +544,11 @@ module Scrivito
|
|
521
544
|
end
|
522
545
|
|
523
546
|
# @api public
|
524
|
-
# This method indicates
|
547
|
+
# This method indicates whether the Obj represents binary data. Binaries are
|
525
548
|
# handled differently in that they are not rendered using the normal layout
|
526
549
|
# but sent as a file. Examples of binary resources are Images or PDFs.
|
527
550
|
#
|
528
|
-
# Every Obj that has
|
551
|
+
# Every Obj that has a +blob+ attribute of the +binary+ type is
|
529
552
|
# considered a binary
|
530
553
|
#
|
531
554
|
# @return true if this Obj represents a binary resource.
|
@@ -535,15 +558,15 @@ module Scrivito
|
|
535
558
|
end
|
536
559
|
|
537
560
|
#
|
538
|
-
# When delivering binary
|
539
|
-
# applied by default.
|
561
|
+
# When delivering binary objects, this method decides whether the image transformations should
|
562
|
+
# be applied by default.
|
540
563
|
#
|
541
|
-
# @api
|
564
|
+
# @api public
|
542
565
|
#
|
543
|
-
# By default this method returns +false+.
|
544
|
-
# Override in subclasses to fit your needs.
|
566
|
+
# By default, this method returns +false+.
|
567
|
+
# Override it in subclasses to fit your needs.
|
545
568
|
#
|
546
|
-
# @note Only relevant for binary
|
569
|
+
# @note Only relevant for binary objects
|
547
570
|
# @see Scrivito::Configuration.default_image_transformation=
|
548
571
|
# @see Scrivito::Binary#transform
|
549
572
|
#
|
@@ -551,14 +574,14 @@ module Scrivito
|
|
551
574
|
false
|
552
575
|
end
|
553
576
|
|
554
|
-
# Returns true if this
|
577
|
+
# Returns true if this Obj is the root Obj.
|
555
578
|
# @api public
|
556
579
|
def root?
|
557
580
|
path == "/"
|
558
581
|
end
|
559
582
|
|
560
583
|
# Returns a list of children excluding the binary? ones unless :all is specfied.
|
561
|
-
# This is
|
584
|
+
# This is useful for creating navigations.
|
562
585
|
# @return [Array<Obj>]
|
563
586
|
# @api public
|
564
587
|
def toclist(*args)
|
@@ -568,15 +591,15 @@ module Scrivito
|
|
568
591
|
toclist
|
569
592
|
end
|
570
593
|
|
571
|
-
# @param objs_to_be_sorted [Array<Scrivito::BasicObj>] unsorted list of
|
572
|
-
# @param list [Array<Scrivito::BasicObj>] list of
|
573
|
-
# @return [Array<Scrivito::BasicObj>] a sorted list of
|
574
|
-
# +objs_to_be_sorted+ but not in +list+ are appended
|
594
|
+
# @param objs_to_be_sorted [Array<Scrivito::BasicObj>] unsorted list of CMS objects
|
595
|
+
# @param list [Array<Scrivito::BasicObj>] list of objects that defines the order
|
596
|
+
# @return [Array<Scrivito::BasicObj>] a sorted list of objects. Objects present in
|
597
|
+
# +objs_to_be_sorted+ but not in +list+ are appended to the end, sorted by +Obj#id+
|
575
598
|
def self.sort_by_list(objs_to_be_sorted, list)
|
576
599
|
(list & objs_to_be_sorted) + (objs_to_be_sorted - list).sort_by(&:id)
|
577
600
|
end
|
578
601
|
|
579
|
-
# This should be a
|
602
|
+
# This should be a Set, because it's faster in this particular case.
|
580
603
|
SYSTEM_KEYS = Set.new(%w[
|
581
604
|
body
|
582
605
|
_id
|
@@ -587,8 +610,8 @@ module Scrivito
|
|
587
610
|
title
|
588
611
|
])
|
589
612
|
|
590
|
-
# Returns the value of
|
591
|
-
# Passing an invalid key will not raise an error
|
613
|
+
# Returns the value of a system or custom attribute specified by its name.
|
614
|
+
# Passing an invalid key will not raise an error but return +nil+.
|
592
615
|
# @api public
|
593
616
|
def [](key)
|
594
617
|
key = key.to_s
|
@@ -609,8 +632,8 @@ module Scrivito
|
|
609
632
|
end
|
610
633
|
end
|
611
634
|
|
612
|
-
# Reloads the attributes of this
|
613
|
-
#
|
635
|
+
# Reloads the attributes of this Obj from the database.
|
636
|
+
# Note that the Ruby class of this Obj instance will NOT change,
|
614
637
|
# even if the obj_class in the database has changed.
|
615
638
|
# @api public
|
616
639
|
def reload
|
@@ -652,10 +675,10 @@ module Scrivito
|
|
652
675
|
end
|
653
676
|
end
|
654
677
|
|
655
|
-
#
|
678
|
+
# Similar to modification but faster if you are only interested in
|
656
679
|
# "new" and "deleted".
|
657
|
-
#
|
658
|
-
# ObjData instead.
|
680
|
+
# This method sometimes does not return a string, but an instance of
|
681
|
+
# ObjData instead. This indicates that the modification is either
|
659
682
|
# UNMODIFIED or EDITED. Which one it is can be determined by comparing
|
660
683
|
# the returned ObjData.
|
661
684
|
def quick_modification(revision)
|
@@ -669,7 +692,7 @@ module Scrivito
|
|
669
692
|
|
670
693
|
if data_for_comparison.present?
|
671
694
|
if modification_attr == 'deleted'
|
672
|
-
# Obj exists in comparison revision
|
695
|
+
# Obj exists in comparison revision but not in current
|
673
696
|
Modification::DELETED
|
674
697
|
else
|
675
698
|
# Obj exists in both revisions, leave the actual comparions
|
@@ -681,7 +704,7 @@ module Scrivito
|
|
681
704
|
# Obj does not exist in either revision
|
682
705
|
Modification::UNMODIFIED
|
683
706
|
else
|
684
|
-
# Obj exists in current
|
707
|
+
# Obj exists in current but not in comparision revision
|
685
708
|
Modification::NEW
|
686
709
|
end
|
687
710
|
end
|
@@ -707,16 +730,16 @@ module Scrivito
|
|
707
730
|
end
|
708
731
|
alias mime_type content_type
|
709
732
|
|
710
|
-
#
|
711
|
-
#
|
733
|
+
# Returns the name extension of the Obj (the part after the last dot).
|
734
|
+
# Returns an empty string if the name of the Obj doesn't have an extension.
|
712
735
|
# @return [String]
|
713
736
|
# @api public
|
714
737
|
def file_extension
|
715
738
|
File.extname(name)[1..-1] || ""
|
716
739
|
end
|
717
740
|
|
718
|
-
# Returns the body (main content) of the Obj for non-binary
|
719
|
-
# Returns +nil+ for binary
|
741
|
+
# Returns the body (main content) of the Obj for non-binary objects.
|
742
|
+
# Returns +nil+ for binary objects.
|
720
743
|
# @return [String]
|
721
744
|
# @api public
|
722
745
|
def body
|
@@ -728,11 +751,11 @@ module Scrivito
|
|
728
751
|
end
|
729
752
|
|
730
753
|
# @api public
|
731
|
-
# This method is intended for
|
732
|
-
# images or
|
754
|
+
# This method is intended for CMS objects that represent binary resources like
|
755
|
+
# images or PDF documents. If the Obj represents a binary file, an instance
|
733
756
|
# of {Binary} is returned.
|
734
757
|
#
|
735
|
-
# This method returns the
|
758
|
+
# This method returns the +blob+ attribute if its type is +binary+.
|
736
759
|
#
|
737
760
|
# @return [Binary, nil]
|
738
761
|
def binary
|
@@ -740,21 +763,21 @@ module Scrivito
|
|
740
763
|
end
|
741
764
|
|
742
765
|
# @api public
|
743
|
-
# This method returns the length
|
744
|
-
# @return [Fixnum] If no binary is set
|
766
|
+
# This method returns the byte length of the binary of the Obj.
|
767
|
+
# @return [Fixnum] If no binary is set, 0 is returned.
|
745
768
|
def binary_length
|
746
769
|
binary.try(:content_length) || 0
|
747
770
|
end
|
748
771
|
|
749
772
|
# @api public
|
750
|
-
# This method returns the content type of the binary of this
|
773
|
+
# This method returns the content type of the binary of this Obj if the binary is set.
|
751
774
|
# @return [String, nil]
|
752
775
|
def binary_content_type
|
753
776
|
binary.try(:content_type)
|
754
777
|
end
|
755
778
|
|
756
779
|
# @api public
|
757
|
-
# This method returns the
|
780
|
+
# This method returns the URL under which the content of this binary is
|
758
781
|
# available to the public if the binary is set.
|
759
782
|
#
|
760
783
|
# See {Binary#url} for details
|
@@ -796,7 +819,7 @@ module Scrivito
|
|
796
819
|
end
|
797
820
|
|
798
821
|
# @api public
|
799
|
-
# Allows accessing the {Scrivito::BasicWidget Widgets} of this Obj
|
822
|
+
# Allows accessing the {Scrivito::BasicWidget Widgets} of this Obj.
|
800
823
|
#
|
801
824
|
# @example Access a widget by its id
|
802
825
|
# obj.widgets['widget_id']
|
@@ -816,9 +839,9 @@ module Scrivito
|
|
816
839
|
#
|
817
840
|
# @api public
|
818
841
|
#
|
819
|
-
# @note This method does not support +Obj+s
|
842
|
+
# @note This method does not support +Obj+s that are +new+.
|
820
843
|
# Please use {Scrivito::BasicObj#destroy Obj#destroy} to destroy them.
|
821
|
-
# @note This method does not support +Obj+s
|
844
|
+
# @note This method does not support +Obj+s that are +deleted+.
|
822
845
|
# Please use {Scrivito::BasicObj.restore Obj.restore} to restore them.
|
823
846
|
#
|
824
847
|
# @raise [ScrivitoError] If the current workspace is +published+.
|
@@ -916,10 +939,6 @@ module Scrivito
|
|
916
939
|
ParentPath.of(path) unless root?
|
917
940
|
end
|
918
941
|
|
919
|
-
def as_client_json
|
920
|
-
data_from_cms.to_h.except(*GENERATED_ATTRIBUTES)
|
921
|
-
end
|
922
|
-
|
923
942
|
def outdated?
|
924
943
|
return false if workspace.published?
|
925
944
|
|
@@ -932,8 +951,64 @@ module Scrivito
|
|
932
951
|
cms_data_for_revision(base_revision) != cms_data_for_revision(published_revision)
|
933
952
|
end
|
934
953
|
|
954
|
+
def transfer_modifications_to(target_workspace)
|
955
|
+
return unless modification
|
956
|
+
if in_revision(target_workspace.revision).try(:modification)
|
957
|
+
raise TransferModificationsError, "Already modified in workspace #{target_workspace.id}"
|
958
|
+
end
|
959
|
+
copy_modifications_to(target_workspace)
|
960
|
+
reset_modifications
|
961
|
+
end
|
962
|
+
|
935
963
|
private
|
936
964
|
|
965
|
+
def copy_modifications_to(target_workspace)
|
966
|
+
case
|
967
|
+
when new? then create_in(target_workspace)
|
968
|
+
when deleted? then destroy_in(target_workspace)
|
969
|
+
else update_in(target_workspace)
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
def create_in(target_workspace)
|
974
|
+
target_workspace.api_request(:post, '/objs', obj: get_attributes)
|
975
|
+
end
|
976
|
+
|
977
|
+
def update_in(target_workspace)
|
978
|
+
update_attributes = fill_in_missing_attributes_as_nil(copyable_attributes)
|
979
|
+
target_workspace.api_request(:put, "/objs/#{id}", obj: update_attributes)
|
980
|
+
end
|
981
|
+
|
982
|
+
def destroy_in(target_workspace)
|
983
|
+
target_workspace.api_request(:delete, "/objs/#{id}")
|
984
|
+
end
|
985
|
+
|
986
|
+
def fill_in_missing_attributes_as_nil(attributes, type_computer=Obj.type_computer)
|
987
|
+
obj_class = type_computer.compute_type_without_fallback(attributes['_obj_class'])
|
988
|
+
missing_attributes = obj_class.attribute_definitions.map(&:name) - attributes.keys
|
989
|
+
|
990
|
+
if attributes['_widget_pool']
|
991
|
+
attributes['_widget_pool'].each do |id, widget_attributes|
|
992
|
+
attributes['_widget_pool'][id] = fill_in_missing_attributes_as_nil(
|
993
|
+
widget_attributes, Widget.type_computer)
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
missing_attributes.each do |attribute_name|
|
998
|
+
attributes[attribute_name] = nil
|
999
|
+
end
|
1000
|
+
|
1001
|
+
attributes
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def reset_modifications
|
1005
|
+
case
|
1006
|
+
when new? then destroy
|
1007
|
+
when deleted? then self.class.restore(id)
|
1008
|
+
else revert
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
|
937
1012
|
def cms_data_for_revision(revision)
|
938
1013
|
return nil unless revision
|
939
1014
|
|
@@ -981,9 +1056,34 @@ module Scrivito
|
|
981
1056
|
end
|
982
1057
|
|
983
1058
|
def copyable_attributes
|
1059
|
+
get_attributes.except(*GENERATED_ATTRIBUTES).except(*UNIQ_ATTRIBUTES)
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
def get_attributes
|
984
1063
|
workspace.api_request(:get, "/objs/#{id}")
|
985
|
-
|
986
|
-
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def copy_binaries(attributes)
|
1067
|
+
attribute_defintions = self.class.find_attribute_definitions(obj_class_name)
|
1068
|
+
destination_obj_id = attributes.fetch(:_id)
|
1069
|
+
|
1070
|
+
Hash[attributes.map do |name, value|
|
1071
|
+
if value && attribute_defintions[name].try(:type) == 'binary'
|
1072
|
+
binary = self[name]
|
1073
|
+
[name, ['binary', copy_binary(destination_obj_id, binary)]]
|
1074
|
+
else
|
1075
|
+
[name, value]
|
1076
|
+
end
|
1077
|
+
end]
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
def copy_binary(destination_obj_id, binary)
|
1081
|
+
normalized_id = CmsRestApi.normalize_path_component(binary.id)
|
1082
|
+
CmsRestApi.put("/blobs/#{normalized_id}/copy", {
|
1083
|
+
destination_obj_id: destination_obj_id,
|
1084
|
+
filename: binary.filename,
|
1085
|
+
content_type: binary.content_type,
|
1086
|
+
})
|
987
1087
|
end
|
988
1088
|
|
989
1089
|
def assert_revertable
|
@@ -1039,10 +1139,14 @@ module Scrivito
|
|
1039
1139
|
Workspace.current.api_request(:post, '/objs', obj: obj_attributes)
|
1040
1140
|
end
|
1041
1141
|
|
1042
|
-
def prepare_attributes_for_rest_api(
|
1043
|
-
widget_pool_attributes = CmsRestApi::WidgetExtractor.call(
|
1142
|
+
def prepare_attributes_for_rest_api(attributes, obj = nil)
|
1143
|
+
widget_pool_attributes, obj_attributes = CmsRestApi::WidgetExtractor.call(attributes, obj)
|
1144
|
+
obj_id = obj ? obj.id : obj_attributes.fetch(:_id)
|
1044
1145
|
workspace = obj ? obj.revision.workspace : Workspace.current
|
1045
|
-
|
1146
|
+
|
1147
|
+
api_attributes = serialize_attributes(
|
1148
|
+
obj_attributes, widget_pool_attributes, workspace, obj_id
|
1149
|
+
)
|
1046
1150
|
|
1047
1151
|
if obj
|
1048
1152
|
widget_pool = api_attributes['_widget_pool']
|
@@ -1054,8 +1158,8 @@ module Scrivito
|
|
1054
1158
|
[api_attributes, widget_pool_attributes]
|
1055
1159
|
end
|
1056
1160
|
|
1057
|
-
def serialize_attributes(obj_attributes, widget_pool_attributes, workspace)
|
1058
|
-
serializer = AttributeSerializer.new(obj_attributes['_obj_class'] || name)
|
1161
|
+
def serialize_attributes(obj_attributes, widget_pool_attributes, workspace, obj_id)
|
1162
|
+
serializer = AttributeSerializer.new(obj_attributes['_obj_class'] || name, obj_id)
|
1059
1163
|
serialized_attributes = serialize_obj_attributes(serializer, obj_attributes)
|
1060
1164
|
serialized_attributes['_widget_pool'] =
|
1061
1165
|
serialize_widget_pool_attributes(serializer, widget_pool_attributes)
|
@@ -1080,6 +1184,10 @@ module Scrivito
|
|
1080
1184
|
def find_attribute_definitions(obj_class, basic_class = self)
|
1081
1185
|
basic_class.type_computer.compute_type(obj_class).attribute_definitions if obj_class
|
1082
1186
|
end
|
1187
|
+
|
1188
|
+
def with_default_id_attribute(attributes)
|
1189
|
+
attributes.reverse_merge(_id: SecureRandom.hex(8))
|
1190
|
+
end
|
1083
1191
|
end
|
1084
1192
|
end
|
1085
1193
|
end
|