scrivito_sdk 1.0.0 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|