scrivito_sdk 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/README.md +1 -1
- data/app/controllers/scrivito/legacy_redirect_controller.rb +11 -0
- data/app/controllers/scrivito/objs_controller.rb +15 -5
- data/app/controllers/scrivito/webservice_controller.rb +4 -3
- data/app/controllers/scrivito/workspaces_controller.rb +24 -29
- data/app/helpers/scrivito_helper.rb +82 -37
- data/app/views/scrivito/objs/binary_no_cache.json.jbuilder +1 -0
- data/app/views/scrivito/objs/search.json.jbuilder +5 -5
- data/app/views/scrivito/webservice/error.json.jbuilder +2 -2
- data/config/ca-bundle.crt +1 -1
- data/config/precedence_routes.rb +51 -48
- data/config/routes.rb +1 -14
- data/lib/assets/javascripts/scrivito_ui.js +2447 -266
- data/lib/assets/stylesheets/scrivito.css +1 -1
- data/lib/assets/stylesheets/scrivito_ui.css +1 -1
- data/lib/generators/scrivito/install/install_generator.rb +12 -0
- data/lib/generators/scrivito/install/templates/config/initializers/scrivito.rb +3 -0
- data/lib/scrivito/attribute_definition.rb +13 -1
- data/lib/scrivito/attribute_deserializer.rb +4 -4
- data/lib/scrivito/attribute_value_renderer.rb +79 -0
- data/lib/scrivito/backend/obj_data_cache.rb +15 -15
- data/lib/scrivito/backend/obj_data_from_rest.rb +1 -21
- data/lib/scrivito/backend/obj_query.rb +2 -2
- data/lib/scrivito/basic_obj.rb +17 -6
- data/lib/scrivito/binary.rb +13 -5
- data/lib/scrivito/cache/chainable.rb +10 -5
- data/lib/scrivito/cache/file_store.rb +4 -0
- data/lib/scrivito/cache/ram_store.rb +4 -0
- data/lib/scrivito/child_list_tag.rb +16 -14
- data/lib/scrivito/client_error.rb +10 -0
- data/lib/scrivito/cms_backend.rb +66 -291
- data/lib/scrivito/cms_data_cache.rb +7 -9
- data/lib/scrivito/cms_dispatch_controller.rb +1 -10
- data/lib/scrivito/cms_field_tag.rb +2 -1
- data/lib/scrivito/cms_rest_api.rb +2 -0
- data/lib/scrivito/cms_routing.rb +26 -22
- data/lib/scrivito/configuration.rb +38 -0
- data/lib/scrivito/connection_manager.rb +69 -0
- data/lib/scrivito/controller_actions.rb +2 -2
- data/lib/scrivito/controller_helper.rb +2 -2
- data/lib/scrivito/date_attribute.rb +4 -1
- data/lib/scrivito/deprecation.rb +5 -4
- data/lib/scrivito/editing_context.rb +2 -2
- data/lib/scrivito/errors.rb +17 -0
- data/lib/scrivito/image_tag.rb +2 -2
- data/lib/scrivito/link_parser.rb +10 -5
- data/lib/scrivito/meta_data_collection.rb +11 -0
- data/lib/scrivito/obj_collection.rb +1 -1
- data/lib/scrivito/obj_facet_value.rb +19 -7
- data/lib/scrivito/obj_params_parser.rb +43 -14
- data/lib/scrivito/obj_search_builder.rb +1 -2
- data/lib/scrivito/obj_search_enumerator/batch.rb +22 -0
- data/lib/scrivito/obj_search_enumerator/batch_iterator.rb +36 -0
- data/lib/scrivito/obj_search_enumerator/query_executor.rb +35 -0
- data/lib/scrivito/obj_search_enumerator.rb +218 -93
- data/lib/scrivito/obj_update_params_parser.rb +1 -0
- data/lib/scrivito/preset_routes.rb +25 -0
- data/lib/scrivito/revision.rb +13 -11
- data/lib/scrivito/route.rb +62 -0
- data/lib/scrivito/routing_extensions.rb +92 -0
- data/lib/scrivito/sdk_engine.rb +4 -0
- data/lib/scrivito/task.rb +77 -0
- data/lib/scrivito/type_computer.rb +3 -3
- data/lib/scrivito/ui_config.rb +4 -0
- data/lib/scrivito/user.rb +24 -18
- data/lib/scrivito/workspace/publish_checker.rb +2 -3
- data/lib/scrivito/workspace.rb +38 -6
- data/lib/scrivito/workspace_data.rb +0 -14
- metadata +14 -10
- data/lib/scrivito/content_service.rb +0 -121
- data/lib/scrivito/content_state.rb +0 -109
- data/lib/scrivito/content_state_caching.rb +0 -47
- data/lib/scrivito/content_state_visitor.rb +0 -19
- data/lib/scrivito/obj_data_from_service.rb +0 -63
- data/lib/scrivito/workspace_data_from_service.rb +0 -43
@@ -2,7 +2,7 @@
|
|
2
2
|
module Scrivito
|
3
3
|
# Provides an enumerator for iterating over the results of searches for CMS objects to retrieve
|
4
4
|
# instances of these objects. This is achieved through the
|
5
|
-
# {http://ruby-doc.org/core
|
5
|
+
# {http://ruby-doc.org/core/Enumerable.html +Enumerable+ mixin}, which provides methods such
|
6
6
|
# as +map+, +select+ or +take+.
|
7
7
|
#
|
8
8
|
# This enumerator is lazy. If, for example, you are looking for {Scrivito::BasicObj Obj}s whose
|
@@ -13,7 +13,7 @@ module Scrivito
|
|
13
13
|
#
|
14
14
|
# To start searching, use one of the {Scrivito::BasicObj Obj} methods that return an
|
15
15
|
# {Scrivito::ObjSearchEnumerator}. The preferred way is to start with
|
16
|
-
# {Scrivito::BasicObj.where Obj.where}.
|
16
|
+
# {Scrivito::BasicObj.where Obj.where} or {Scrivito::BasicObj.all Obj.all}.
|
17
17
|
#
|
18
18
|
# == Currently available fields and their values
|
19
19
|
#
|
@@ -24,9 +24,18 @@ module Scrivito
|
|
24
24
|
# [+:_name+] Name of an {Scrivito::BasicObj Obj}. This is a +string+ field.
|
25
25
|
# [+:_obj_class+] Object class of an {Scrivito::BasicObj Obj}. This is a +string+ field.
|
26
26
|
# [+:_permalink+] Permalink of an {Scrivito::BasicObj Obj}. This is a +string+ field.
|
27
|
-
# [+:_last_changed+] Date of last change
|
27
|
+
# [+:_last_changed+] Date of last change to an {Scrivito::BasicObj Obj}.
|
28
28
|
# [every +_:custom_attribute_+] Custom attribute of an {Scrivito::BasicObj Obj}. Note that depending on the attribute type (e.g. an +html+ field), some operators cannot be applied.
|
29
29
|
#
|
30
|
+
# === Meta Data
|
31
|
+
#
|
32
|
+
# If an {Scrivito::BasicObj Obj} has a +binary+ attribute named +blob+, the meta data of this
|
33
|
+
# attribute is searchable. For a full list of the available meta data attributes, see the
|
34
|
+
# documentation of the {Scrivito::MetaDataCollection MetaDataCollection}. The meta data
|
35
|
+
# attribute name needs to be prefixed with +blob:+ when searching for it. So, for example,
|
36
|
+
# when searching for the width, you need to specify the attribute name using +blob:width+.
|
37
|
+
# Binary attributes other than +blob+ are not searchable.
|
38
|
+
#
|
30
39
|
# == Currently available operators
|
31
40
|
#
|
32
41
|
# === +contains+ and +contains_prefix+
|
@@ -54,24 +63,15 @@ module Scrivito
|
|
54
63
|
#
|
55
64
|
# ✔ "Every" (case insensitive)
|
56
65
|
#
|
57
|
-
# === +equals+
|
66
|
+
# === +equals+
|
58
67
|
#
|
59
|
-
#
|
68
|
+
# The +equals+ operator is intended for programmatic comparisons of string and date values.
|
60
69
|
#
|
61
|
-
# The
|
70
|
+
# The operator has some limits with regard to string length.
|
62
71
|
# String values are only guaranteed to be considered if they are at most 1000 characters in length.
|
63
72
|
# String values of more than 1000 characters may be ignored by these operators.
|
64
73
|
#
|
65
|
-
#
|
66
|
-
# Only prefixes of up to 20 characters are guaranteed to be matched.
|
67
|
-
# If you supply a prefix of more than 20 characters, the additional characters may be ignored.
|
68
|
-
#
|
69
|
-
# When combined with the system attribute +_path+, the operator +prefix+ has some special functionality:
|
70
|
-
# There is not precision limit, i.e. a prefix of arbitrary length may be used to match on +_path+.
|
71
|
-
# Also, prefix matching on +_path+ automatically matches entire path components,
|
72
|
-
# i.e. the prefix matching is delimited by slashes (the character +'/'+).
|
73
|
-
#
|
74
|
-
# For +equals+ and +starts_with+, the examples are based on the following field value:
|
74
|
+
# For +equals+, the examples are based on the following field value:
|
75
75
|
# "Some content."
|
76
76
|
#
|
77
77
|
# [+:equals+] The +field+ value needs to be identical to the +value+ of this subquery.
|
@@ -84,6 +84,22 @@ module Scrivito
|
|
84
84
|
#
|
85
85
|
# ✘ "Some" (not exact value)
|
86
86
|
#
|
87
|
+
# === +starts_with+
|
88
|
+
#
|
89
|
+
# The +starts_with+ is intended for programmatic comparions of string values.
|
90
|
+
#
|
91
|
+
# The +starts_with+ operator has a precision limit:
|
92
|
+
# Only prefixes of up to 20 characters are guaranteed to be matched.
|
93
|
+
# If you supply a prefix of more than 20 characters, the additional characters may be ignored.
|
94
|
+
#
|
95
|
+
# When combined with the system attribute +_path+, the operator +starts_with+ has some special functionality:
|
96
|
+
# There is not precision limit, i.e. a prefix of arbitrary length may be used to match on +_path+.
|
97
|
+
# Also, prefix matching on +_path+ automatically matches entire path components,
|
98
|
+
# i.e. the prefix matching is delimited by slashes (the character +'/'+).
|
99
|
+
#
|
100
|
+
# For +starts_with+, the examples are based on the following field value:
|
101
|
+
# "Some content."
|
102
|
+
#
|
87
103
|
# [+:starts_with+] The +field+ value needs to start exactly with the +value+ of this subquery.
|
88
104
|
#
|
89
105
|
# Applicable to +string+, +stringlist+, +enum+ and +multienum+ fields.
|
@@ -98,7 +114,9 @@ module Scrivito
|
|
98
114
|
#
|
99
115
|
# === +is_less_than+ and +is_greater_than+
|
100
116
|
#
|
101
|
-
# These operators are intended for
|
117
|
+
# These operators are intended for comparing +date+ values or numerical metadata, for example the width of an image.
|
118
|
+
# It only considers attributes of {Scrivito::BasicObj Obj}s and _not_ of {Scrivito::BasicWidget Widget}s.
|
119
|
+
# Therefore, {Scrivito::BasicWidget Widget} attributes are not searchable using the +is_less_than+ and +is_greater_than+ operators.
|
102
120
|
#
|
103
121
|
# For +is_less_than+ and +is_greater_than+, the examples are based on the following date value:
|
104
122
|
# +Time.new(2000,01,01,00,00,00)+
|
@@ -133,9 +151,10 @@ module Scrivito
|
|
133
151
|
attr_reader :workspace
|
134
152
|
|
135
153
|
attr_reader :query
|
136
|
-
def initialize(workspace)
|
154
|
+
def initialize(workspace, batch_size = nil)
|
137
155
|
@workspace = workspace
|
138
|
-
@
|
156
|
+
@batch_size = batch_size
|
157
|
+
@options = { offset: 0 }
|
139
158
|
end
|
140
159
|
|
141
160
|
# @group Chainable methods
|
@@ -168,7 +187,7 @@ module Scrivito
|
|
168
187
|
"Valid operators are: #{valid_boost_operators.join(', ')}"
|
169
188
|
end
|
170
189
|
end
|
171
|
-
|
190
|
+
reset_for_changed_query
|
172
191
|
@query = (query || []) + [subquery]
|
173
192
|
|
174
193
|
self
|
@@ -197,7 +216,7 @@ module Scrivito
|
|
197
216
|
end
|
198
217
|
subquery = {:field => field, :operator => real_operator, :value => convert_value(value),
|
199
218
|
:negate => true}
|
200
|
-
|
219
|
+
reset_for_changed_query
|
201
220
|
@query = (query || []) + [subquery]
|
202
221
|
|
203
222
|
self
|
@@ -210,39 +229,66 @@ module Scrivito
|
|
210
229
|
# There is a precision limit when sorting string values:
|
211
230
|
# Only the first 50 characters of a string are guaranteed to be considered when sorting search results.
|
212
231
|
#
|
213
|
-
# @
|
214
|
-
#
|
232
|
+
# @overload order(field_name)
|
233
|
+
# @param [Symbol, String] field_name This parameter specifies the field by
|
234
|
+
# which the hits are sorted (e.g. +:_path+).
|
235
|
+
#
|
236
|
+
# @overload order(field_and_direction)
|
237
|
+
# @param [Hash] field_and_direction The field name and sort direction can be
|
238
|
+
# specfied as the key and value of a hash. Valid directions are
|
239
|
+
# +:asc+ and +:desc+. The default is +:asc+.
|
240
|
+
#
|
241
|
+
# @example Sorting descending
|
242
|
+
# Obj.all.order(_last_changed: :desc)
|
243
|
+
#
|
215
244
|
# @return [Scrivito::ObjSearchEnumerator]
|
216
245
|
# @api public
|
217
246
|
def order(field_name)
|
247
|
+
field_name, direction = if field_name.is_a?(Hash)
|
248
|
+
field_name.to_a.first
|
249
|
+
else
|
250
|
+
[field_name, :asc]
|
251
|
+
end
|
252
|
+
|
218
253
|
options[:sort_by] = field_name
|
254
|
+
options[:sort_order] = direction.to_sym
|
219
255
|
|
220
256
|
self
|
221
257
|
end
|
222
258
|
|
223
259
|
# Reverses the order of the results. Requires {#order} to be applied before.
|
224
260
|
# @return [Scrivito::ObjSearchEnumerator]
|
261
|
+
# @deprecated This method is deprecated and will be removed in the next major
|
262
|
+
# version. Please specify the direction using {#order}.
|
225
263
|
# @api public
|
226
264
|
def reverse_order
|
265
|
+
Scrivito::Deprecation.warn_method("reverse_order", "order")
|
227
266
|
options[:sort_by].present? or raise "A search order has to be specified"\
|
228
267
|
" before reverse_order can be applied."
|
229
|
-
|
268
|
+
options[:sort_order] = options[:sort_order] == :asc ? :desc : :asc
|
230
269
|
|
231
270
|
self
|
232
271
|
end
|
233
272
|
|
273
|
+
#
|
234
274
|
# Number of search results to be returned by each of the internal search requests.
|
275
|
+
#
|
276
|
+
# @api public
|
277
|
+
#
|
235
278
|
# The default is +10+.
|
236
279
|
#
|
237
|
-
# Scrivito makes a best effort to return the given number of search results,
|
238
|
-
#
|
239
|
-
#
|
280
|
+
# Scrivito makes a best effort to return the given number of search results, but may under
|
281
|
+
# certain circumstances return larger or smaller batches due to technical reasons.
|
282
|
+
#
|
283
|
+
# @param [Integer] size number of search results to be returned by each of the internal search
|
284
|
+
# requests. Scrivito tries to honor the requested +size+ as much as possible, but there is no
|
285
|
+
# guarantee. At the time of writing, +size+ is capped at +100+, for example.
|
240
286
|
#
|
241
|
-
# @param [Integer] size A value in the range from +1+ to +100+.
|
242
287
|
# @return [Scrivito::ObjSearchEnumerator]
|
243
|
-
#
|
288
|
+
#
|
244
289
|
def batch_size(size)
|
245
|
-
|
290
|
+
@batch_size = size
|
291
|
+
@preload_search_result = true
|
246
292
|
|
247
293
|
self
|
248
294
|
end
|
@@ -253,7 +299,6 @@ module Scrivito
|
|
253
299
|
# @return [Scrivito::ObjSearchEnumerator]
|
254
300
|
# @api public
|
255
301
|
def offset(amount)
|
256
|
-
options[:offset] ||= 0
|
257
302
|
options[:offset] += amount
|
258
303
|
|
259
304
|
self
|
@@ -272,21 +317,15 @@ module Scrivito
|
|
272
317
|
# @return [void]
|
273
318
|
# @api public
|
274
319
|
def each
|
275
|
-
|
276
|
-
current_batch, total = fetch_next_batch(offset)
|
277
|
-
loop do
|
278
|
-
if current_batch.size == 0
|
279
|
-
if offset < total
|
280
|
-
current_batch, total = fetch_next_batch(offset)
|
281
|
-
else
|
282
|
-
raise StopIteration
|
283
|
-
end
|
284
|
-
end
|
320
|
+
iterator = BatchIterator.new(workspace, search_dsl_params, @preloaded_batch)
|
285
321
|
|
286
|
-
|
287
|
-
|
288
|
-
|
322
|
+
iterator.each do |batch|
|
323
|
+
batch.objs.each do |obj|
|
324
|
+
yield obj
|
325
|
+
end
|
289
326
|
end
|
327
|
+
|
328
|
+
@size = iterator.total
|
290
329
|
end
|
291
330
|
|
292
331
|
# The total number of hits.
|
@@ -321,9 +360,7 @@ module Scrivito
|
|
321
360
|
# methods from +Enumerable+, for example +take+.
|
322
361
|
# @api public
|
323
362
|
def load_batch
|
324
|
-
|
325
|
-
|
326
|
-
next_batch.first
|
363
|
+
fetch_batch.objs
|
327
364
|
end
|
328
365
|
|
329
366
|
# @api public
|
@@ -332,25 +369,38 @@ module Scrivito
|
|
332
369
|
# @api public
|
333
370
|
alias_method :count, :size
|
334
371
|
|
335
|
-
# @api public
|
336
|
-
# Perform a faceted search over
|
372
|
+
# @api public
|
373
|
+
# Perform a faceted search over up to ten attributes to retrieve structured results for individual values of these attributes.
|
337
374
|
#
|
338
|
-
# Applicable to
|
375
|
+
# Applicable to attributes of the following types: +string+, +stringlist+, +enum+, +multienum+.
|
339
376
|
#
|
340
377
|
# Please note that there is a precision limit for faceting:
|
341
378
|
# Only the first 50 characters of a string are guaranteed to be considered for faceting.
|
342
379
|
# If two string values have the same first 50 characters, they may be grouped into the same facet value.
|
343
380
|
#
|
344
|
-
#
|
345
|
-
#
|
346
|
-
#
|
347
|
-
# @option options [Integer] :include_objs number of Objs to fetch for each unique value. Defaults to 0.
|
381
|
+
# Please note that by default {Scrivito::ObjSearchEnumerator#facet} does not preload the first batch of the search results.
|
382
|
+
# In order to reduce the number of search requests, +batch_size+ can be explicitly set using the {Scrivito::ObjSearchEnumerator#batch_size} method.
|
383
|
+
# This causes Scrivito to preload the first batch of the search results.
|
348
384
|
#
|
349
|
-
# @
|
350
|
-
#
|
351
|
-
#
|
385
|
+
# @overload facet(attribute, options={})
|
386
|
+
# Single-attribute faceting request.
|
387
|
+
# @param [String] attribute the name of an attribute.
|
388
|
+
# @param [Hash] options the options to facet a request with.
|
389
|
+
# @option options [Integer] :limit maximum number of unique values to return. Defaults to 20.
|
390
|
+
# @option options [Integer] :include_objs number of Objs to fetch for each unique value. Defaults to 0.
|
391
|
+
# @return [Array<Scrivito::ObjFacetValue>]
|
392
|
+
# in the ++facets++ parameter.
|
393
|
+
# The values of the hash are lists of {Scrivito::ObjFacetValue}.
|
394
|
+
# @overload facet(facets)
|
395
|
+
# Multi-attribute faceting request. The maximum number of attributes that may be specified is 10.
|
396
|
+
# @param [Hash] facets a hash where the keys are attribute names and the values are options.
|
397
|
+
# The available options are identical to the options for single faceting requests.
|
398
|
+
# @return [Hash] a hash where the keys are identical to the keys given.
|
399
|
+
# A list of unique values that were found for the given attribute name. The list is
|
400
|
+
# ordered by frequency, i.e. values occurring more frequently come first.
|
401
|
+
# @raise [Scrivito::ClientError] If the number of attributes exceeds 10.
|
352
402
|
#
|
353
|
-
# @example Faceted request: colors of _big_ balloons
|
403
|
+
# @example Faceted request: colors of _big_ balloons:
|
354
404
|
# facets = Balloon.where(:size, :equals, "big").facet("color")
|
355
405
|
#
|
356
406
|
# # Big balloons come in 3 colors:
|
@@ -371,14 +421,14 @@ module Scrivito
|
|
371
421
|
# blue_balloons.name #=> "blue"
|
372
422
|
# blue_balloons.count #=> 1
|
373
423
|
#
|
374
|
-
# @example Faceted request with limit: at most 2 colors of big balloons
|
424
|
+
# @example Faceted request with limit: at most 2 colors of big balloons:
|
375
425
|
# facets = Balloon.where(:size, :equals, "big").facet("color", limit: 2)
|
376
426
|
#
|
377
427
|
# # Although there are 3 different colors of big balloons,
|
378
428
|
# # only the first 2 colors will be taken into account.
|
379
429
|
# facets.count # => 2
|
380
430
|
#
|
381
|
-
# @example Faceted request with included Objs
|
431
|
+
# @example Faceted request with included Objs:
|
382
432
|
# facets = Balloon.where(:size, :equals, "big").facet("color", include_objs: 2)
|
383
433
|
#
|
384
434
|
# facets.each do |facet|
|
@@ -387,7 +437,7 @@ module Scrivito
|
|
387
437
|
# end
|
388
438
|
# end
|
389
439
|
#
|
390
|
-
# # If there are
|
440
|
+
# # If there are 2 big red balloons, 2 big green balloons and 1 big blue balloon,
|
391
441
|
# # then this will produce:
|
392
442
|
#
|
393
443
|
# "big red Balloon"
|
@@ -396,19 +446,90 @@ module Scrivito
|
|
396
446
|
# "big green Balloon"
|
397
447
|
# "big blue Balloon"
|
398
448
|
#
|
449
|
+
# @example Multiple faceting request:
|
450
|
+
# facets = Balloon.where(:size, :equals, "big").facet(
|
451
|
+
# color: {limit: 3, include_objs: 5},
|
452
|
+
# motif: {limit: 3, include_objs: 5}
|
453
|
+
# )
|
454
|
+
#
|
455
|
+
# color_facet_obj_values = facets[:color]
|
456
|
+
# motif_facet_obj_values = facets[:motif]
|
457
|
+
#
|
458
|
+
# color_facet_obj_values.each do |facet|
|
459
|
+
# facet.included_objs.each do |obj|
|
460
|
+
# puts "#{obj.size} #{obj.color} #{obj.class}"
|
461
|
+
# end
|
462
|
+
# end
|
463
|
+
#
|
464
|
+
# motif_facet_obj_values.each do |facet|
|
465
|
+
# facet.included_objs.each do |obj|
|
466
|
+
# puts "#{obj.size} #{obj.motif} #{obj.class}"
|
467
|
+
# end
|
468
|
+
# end
|
469
|
+
#
|
470
|
+
# # If there are 2 big red balloons, 2 big green balloons and 1 big blue balloon,
|
471
|
+
# # this will produce:
|
472
|
+
#
|
473
|
+
# "big red Balloon"
|
474
|
+
# "big red Balloon"
|
475
|
+
# "big green Balloon"
|
476
|
+
# "big green Balloon"
|
477
|
+
# "big blue Balloon"
|
478
|
+
#
|
479
|
+
# # If there are 1 big birthday balloon and 1 big wedding balloon,
|
480
|
+
# # this will produce:
|
481
|
+
#
|
482
|
+
# "big birthday Balloon"
|
483
|
+
# "big wedding Balloon"
|
484
|
+
#
|
485
|
+
# @example Faceted +where+ query with +batch_size+:
|
486
|
+
# big_balloons = Balloon.where(:size, :equals, "big")
|
487
|
+
#
|
488
|
+
# # Without preloading
|
489
|
+
# balloon_colors = big_balloons.facet("color")
|
490
|
+
# first_ten_balloons = big_balloons.take(10) # This will cause a search request.
|
491
|
+
#
|
492
|
+
# # With preloading
|
493
|
+
# big_balloons.batch_size(10) # Make Scrivito preload the first ten balloons.
|
494
|
+
# balloon_colors = big_balloons.facet("color")
|
495
|
+
# first_ten_balloons = big_balloons.take(10) # This will cause _no_ search request.
|
496
|
+
#
|
399
497
|
# @raise [Scrivito::ClientError] If the maximum number of results has been exceeded.
|
400
|
-
# The
|
498
|
+
# The number of results is limited to 100 with respect to the facets themselves and the included Objs.
|
401
499
|
#
|
402
|
-
def facet(
|
403
|
-
|
404
|
-
|
405
|
-
|
500
|
+
def facet(*args)
|
501
|
+
if args.length == 1 && args[0].is_a?(Hash)
|
502
|
+
return {} if args[0].empty?
|
503
|
+
facets_params = multiple_facet_params(args)
|
504
|
+
get_facet_value_objs(facets_params, args[0].keys)
|
505
|
+
else
|
506
|
+
facets_params = [single_facet_params(*args)]
|
507
|
+
attribute_name = args[0]
|
508
|
+
result = get_facet_value_objs(facets_params, [attribute_name])
|
509
|
+
result[attribute_name]
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def fetch_batch(continuation=nil)
|
514
|
+
batch =
|
515
|
+
if @preloaded_batch && !continuation
|
516
|
+
@preloaded_batch
|
517
|
+
else
|
518
|
+
QueryExecutor.new(workspace).call(search_dsl_params, continuation)
|
519
|
+
end
|
520
|
+
|
521
|
+
@size = batch.total
|
522
|
+
batch
|
406
523
|
end
|
407
524
|
|
408
525
|
private
|
409
526
|
|
410
527
|
attr_reader :options
|
411
528
|
|
529
|
+
def reset_for_changed_query
|
530
|
+
@size, @preloaded_batch = nil
|
531
|
+
end
|
532
|
+
|
412
533
|
def convert_value(value)
|
413
534
|
if value.kind_of?(Array)
|
414
535
|
value.map{ |v| convert_single_value(v) }
|
@@ -449,6 +570,18 @@ module Scrivito
|
|
449
570
|
result
|
450
571
|
end
|
451
572
|
|
573
|
+
def multiple_facet_params(facets)
|
574
|
+
facet_params = []
|
575
|
+
facets.first.map do |k, v|
|
576
|
+
facet_params << single_facet_params(k, v)
|
577
|
+
end
|
578
|
+
facet_params
|
579
|
+
end
|
580
|
+
|
581
|
+
def single_facet_params(attribute, options = {})
|
582
|
+
{ attribute: attribute }.merge!(options)
|
583
|
+
end
|
584
|
+
|
452
585
|
def get_objs_facet_ids(facet)
|
453
586
|
result = []
|
454
587
|
if included_ids = facet["results"]
|
@@ -460,27 +593,33 @@ module Scrivito
|
|
460
593
|
def get_facet_value_objs(facets_params, attributes_list = [])
|
461
594
|
result = attributes_list.each_with_object({}) { |v,h| h[v] = [] }
|
462
595
|
included_objs_ids = []
|
463
|
-
params = { facets: facets_params }
|
464
596
|
|
465
|
-
|
466
|
-
offset = options[:offset] || 0
|
467
|
-
params.merge! search_dsl(offset)
|
468
|
-
end
|
597
|
+
params = prepare_facet_search_params facets_params
|
469
598
|
|
470
|
-
|
599
|
+
batch = QueryExecutor.new(workspace).call(params)
|
600
|
+
@preloaded_batch = batch if @preload_search_result
|
471
601
|
|
472
|
-
|
473
|
-
request_result['facets'].each do |facets_array|
|
602
|
+
batch.facets.each do |facets_array|
|
474
603
|
included_objs_ids += get_all_facets_ids(facets_array)
|
475
604
|
end
|
476
605
|
|
477
|
-
obj_collection =
|
478
|
-
|
606
|
+
obj_collection = workspace.objs.find(included_objs_ids)
|
607
|
+
batch.facets.each_with_index do |facets_array, index|
|
479
608
|
result[result.keys[index]] += create_facet_value_objs(facets_array, obj_collection)
|
480
609
|
end
|
481
610
|
result
|
482
611
|
end
|
483
612
|
|
613
|
+
def prepare_facet_search_params(facet_params)
|
614
|
+
params = { facets: facet_params }
|
615
|
+
|
616
|
+
if query
|
617
|
+
params.merge! search_dsl_params
|
618
|
+
end
|
619
|
+
|
620
|
+
params.reverse_merge(size: 0)
|
621
|
+
end
|
622
|
+
|
484
623
|
def operator_mapping(operator)
|
485
624
|
case operator.to_sym
|
486
625
|
when :contains
|
@@ -496,29 +635,15 @@ module Scrivito
|
|
496
635
|
when :is_less_than
|
497
636
|
:less_than
|
498
637
|
else
|
499
|
-
raise "Operator '#{operator}'
|
638
|
+
raise "Operator '#{operator}' is not valid!"
|
500
639
|
end
|
501
640
|
end
|
502
641
|
|
503
|
-
def
|
504
|
-
request_result = CmsBackend.instance.search_objs(workspace, search_dsl(offset))
|
505
|
-
|
506
|
-
obj_ids = request_result['results'].map { |result| result['id'] || result['_id'] }
|
507
|
-
objs = workspace.objs.find_including_deleted(obj_ids)
|
508
|
-
|
509
|
-
@size = request_result['total'].to_i
|
510
|
-
|
511
|
-
[objs, @size]
|
512
|
-
end
|
513
|
-
|
514
|
-
def search_dsl(offset)
|
642
|
+
def search_dsl_params
|
515
643
|
patches = {
|
516
|
-
offset: offset,
|
517
644
|
query: query,
|
518
645
|
}
|
519
|
-
if @
|
520
|
-
patches[:sort_order] = options[:sort_by].present? ? :desc : :asc
|
521
|
-
end
|
646
|
+
patches[:size] = @batch_size if @batch_size
|
522
647
|
|
523
648
|
if @include_deleted
|
524
649
|
patches[:options] = {
|
@@ -18,6 +18,7 @@ module Scrivito
|
|
18
18
|
params['_widget_pool'].each_pair do |widget_id, widget_params|
|
19
19
|
if widget_params.present?
|
20
20
|
widget = obj.widgets[widget_id]
|
21
|
+
raise_widget_not_found_error(widget_id) unless widget
|
21
22
|
widget_pool[widget] = convert_field_params(widget_params, widget.attribute_definitions)
|
22
23
|
end
|
23
24
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Scrivito
|
2
|
+
module PresetRoutes
|
3
|
+
def self.install_into(route_set)
|
4
|
+
return if Scrivito::Configuration.scrivito_route_enabled?
|
5
|
+
|
6
|
+
Scrivito::Configuration.with_scrivito_route_enabled do
|
7
|
+
route_set.draw do
|
8
|
+
scrivito_route '/', using: "homepage", via: :all
|
9
|
+
|
10
|
+
if Scrivito::Configuration.legacy_routing
|
11
|
+
scrivito_route ':id(/*slug)', using: "slug_id", via: :all
|
12
|
+
else
|
13
|
+
scrivito_route '(/)(*slug-):id', using: "slug_id", via: :all
|
14
|
+
|
15
|
+
match ':id(/*slug)', to: 'scrivito/legacy_redirect#index', via: :all, constraints: {
|
16
|
+
id: /[a-z0-9]{16}/
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
scrivito_route '/*permalink', using: "permalink", format: false, via: :all
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/scrivito/revision.rb
CHANGED
@@ -5,10 +5,6 @@ class Revision < Struct.new(:id, :workspace, :base)
|
|
5
5
|
super(*options.values_at(:id, :workspace, :base))
|
6
6
|
end
|
7
7
|
|
8
|
-
def content_state
|
9
|
-
base ? workspace.base_content_state : workspace.content_state
|
10
|
-
end
|
11
|
-
|
12
8
|
def content_state_id
|
13
9
|
base ? workspace.base_content_state_id : workspace.content_state_id
|
14
10
|
end
|
@@ -41,18 +37,24 @@ class Revision < Struct.new(:id, :workspace, :base)
|
|
41
37
|
|
42
38
|
private
|
43
39
|
|
44
|
-
def internal_obj_search(query, result)
|
45
|
-
response = workspace.api_request(:get, "/objs/search",
|
46
|
-
query: query,
|
47
|
-
|
40
|
+
def internal_obj_search(query, result, continuation=nil, tentative=false)
|
41
|
+
response = workspace.api_request(:get, "/objs/search",
|
42
|
+
query: query,
|
43
|
+
include_deleted: true,
|
44
|
+
size: 100,
|
45
|
+
continuation: continuation,
|
46
|
+
consistent_with: content_state_id
|
47
|
+
)
|
48
48
|
|
49
49
|
cur_result = response['results'].map { |obj_data| obj_data['id'] }
|
50
50
|
result += cur_result
|
51
|
+
continuation = response['continuation']
|
52
|
+
tentative ||= !!response['tentative']
|
51
53
|
|
52
|
-
if
|
53
|
-
result
|
54
|
+
if continuation
|
55
|
+
internal_obj_search(query, result, continuation, tentative)
|
54
56
|
else
|
55
|
-
|
57
|
+
[result.uniq, tentative]
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Scrivito
|
2
|
+
|
3
|
+
class Route
|
4
|
+
|
5
|
+
class << self
|
6
|
+
VALID_ROUTE_NAMES = %i(homepage slug_id permalink).freeze
|
7
|
+
|
8
|
+
def register(route_set, name)
|
9
|
+
assert_valid_route_name(name)
|
10
|
+
registry(route_set)[name] = new(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def defined?(route_set, name)
|
14
|
+
!!registry(route_set)[name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(route_set, name)
|
18
|
+
registry(route_set)[name] or raise InternalError, "route #{name} not found"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def registry(route_set)
|
24
|
+
@registry ||= {}
|
25
|
+
@registry[route_set] ||= {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_valid_route_name(name)
|
29
|
+
unless VALID_ROUTE_NAMES.include?(name)
|
30
|
+
valid_values = VALID_ROUTE_NAMES.join(', ')
|
31
|
+
raise ScrivitoError,
|
32
|
+
%("#{name}" is not a valid scrivito route name. Valid values are: #{valid_values}.)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(name)
|
38
|
+
@name = name
|
39
|
+
end
|
40
|
+
|
41
|
+
def helper_name
|
42
|
+
# use a random name to prevent users from getting the idea
|
43
|
+
# that the internally unsed routing helpers might be a stable API
|
44
|
+
random_segment = Digest::SHA1.hexdigest(@name.to_s)[0..15]
|
45
|
+
@helper_name ||= "scrivito_#{random_segment}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_path(context, options = {})
|
49
|
+
generate(context, :path, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_url(context, options = {})
|
53
|
+
generate(context, :url, options)
|
54
|
+
end
|
55
|
+
|
56
|
+
def generate(context, path_or_url, options = {})
|
57
|
+
context.public_send("#{helper_name}_#{path_or_url}", options)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|