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
@@ -210,6 +210,7 @@ module Scrivito
|
|
210
210
|
self.default_image_transformation = {}
|
211
211
|
self.choose_homepage_callback = -> (env) { Obj.root }
|
212
212
|
self.find_user_proc = nil
|
213
|
+
self.inject_preset_routes = true
|
213
214
|
reset_editing_auth_callback!
|
214
215
|
end
|
215
216
|
|
@@ -231,11 +232,48 @@ module Scrivito
|
|
231
232
|
|
232
233
|
|
233
234
|
# @api public
|
235
|
+
# @deprecated The legacy routing is deprecated and will be removed in the next major
|
236
|
+
# version of Scrivito.
|
234
237
|
#
|
235
238
|
# Scrivito changed its routing to a slug first url scheme. This configuration option
|
236
239
|
# allows you to switch back to the old id first url scheme.
|
237
240
|
attr_accessor :legacy_routing
|
238
241
|
|
242
|
+
def legacy_routing=(enabled)
|
243
|
+
if enabled
|
244
|
+
Scrivito::Deprecation.warn(%[
|
245
|
+
The legacy routing is deprecated and will be removed in the next major version of Scrivito.
|
246
|
+
Please use the new scrivito_route api to replicate the legacy routes:
|
247
|
+
scrivito_route '/', using: 'homepage', via: :all
|
248
|
+
scrivito_route '(/):id/*slug', using: 'slug_id', via: :all
|
249
|
+
scrivito_route '/*permalink', using: 'permalink', via: all
|
250
|
+
])
|
251
|
+
end
|
252
|
+
@legacy_routing = enabled
|
253
|
+
end
|
254
|
+
|
255
|
+
# @api public
|
256
|
+
#
|
257
|
+
# The +inject_preset_routes+ configuration is enabled by default and adds the default
|
258
|
+
# Scrivito routing to your application routes. It can be disabled by setting it to
|
259
|
+
# +false+ which lets you use {RoutingExtensions#scrivito_route scrivito_route} to
|
260
|
+
# customize the routing used by Scrivito.
|
261
|
+
attr_accessor :inject_preset_routes
|
262
|
+
|
263
|
+
def scrivito_route_enabled?
|
264
|
+
inject_preset_routes == false
|
265
|
+
end
|
266
|
+
|
267
|
+
def with_scrivito_route_enabled
|
268
|
+
begin
|
269
|
+
initial_value = inject_preset_routes
|
270
|
+
self.inject_preset_routes = false
|
271
|
+
yield
|
272
|
+
ensure
|
273
|
+
self.inject_preset_routes = initial_value
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
239
277
|
attr_accessor :choose_homepage_callback, :check_batch_size
|
240
278
|
|
241
279
|
#
|
@@ -61,11 +61,18 @@ module Scrivito
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
# for testing purposes
|
65
|
+
def connect_count
|
66
|
+
@connect_count || 0
|
67
|
+
end
|
68
|
+
|
64
69
|
private
|
65
70
|
|
66
71
|
attr_accessor :connection
|
67
72
|
|
68
73
|
def ensure_started(timeout)
|
74
|
+
cleanup_dead_connection
|
75
|
+
|
69
76
|
if @connection && @connection.started?
|
70
77
|
configure_timeout(@connection, timeout)
|
71
78
|
else
|
@@ -76,13 +83,75 @@ module Scrivito
|
|
76
83
|
conn.cert_store = self.class.cert_store
|
77
84
|
end
|
78
85
|
configure_timeout(conn, timeout)
|
86
|
+
|
87
|
+
# keep_alive_timeout is not a timeout as in "wait no longer than X",
|
88
|
+
# but specifies how long a connection will be reused if it was idle.
|
89
|
+
# therefore the 'timeout' parameter is not applied here.
|
90
|
+
# instead we use a large value to maximize connection reuse.
|
91
|
+
# (ELB uses a keep alive timeout of 60 seconds).
|
92
|
+
conn.keep_alive_timeout = 59
|
93
|
+
|
79
94
|
retry_twice_on_socket_error do
|
80
95
|
conn.start
|
81
96
|
end
|
97
|
+
|
98
|
+
increase_connect_count
|
82
99
|
@connection = conn
|
83
100
|
end
|
84
101
|
end
|
85
102
|
|
103
|
+
def increase_connect_count
|
104
|
+
@connect_count ||= 0
|
105
|
+
@connect_count += 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def cleanup_dead_connection
|
109
|
+
ensure_finished if connection_error?
|
110
|
+
end
|
111
|
+
|
112
|
+
# test if the http server closed the connection
|
113
|
+
# (i.e. due to a server-side keep alive timeout)
|
114
|
+
#
|
115
|
+
# if the server closes a connection, the socket of the connection
|
116
|
+
# is at EOF (End-Of-File). Using the connection would cause an error.
|
117
|
+
# Unfortunatly net/http does not detect this.
|
118
|
+
#
|
119
|
+
# Running into an error would be okay-ish for idempotent http requests,
|
120
|
+
# since retry is possible, but for non-idempotent requests (POST) the error
|
121
|
+
# would raise to the user.
|
122
|
+
#
|
123
|
+
# So we have to hack our way around net/http to access the socket directly.
|
124
|
+
# In order to do that, internals of net/http are accessed.
|
125
|
+
# If these internals change in future ruby versions, this method should
|
126
|
+
# simply returns `nil` (i.e. connection error are not detected)
|
127
|
+
# but not raise errors.
|
128
|
+
def connection_error?
|
129
|
+
return unless @connection
|
130
|
+
|
131
|
+
# compare: http://git.io/vltBR
|
132
|
+
socket = @connection.instance_variable_get("@socket")
|
133
|
+
return unless socket
|
134
|
+
|
135
|
+
# compare: http://git.io/vltRu
|
136
|
+
io = socket.try(:io)
|
137
|
+
return unless io && io.respond_to?(:read_nonblock)
|
138
|
+
|
139
|
+
begin
|
140
|
+
io.read_nonblock(1)
|
141
|
+
|
142
|
+
# if read_nonblock returns, there is unexpected data in the socket
|
143
|
+
# this indicates a connection problem, since http servers should never
|
144
|
+
# send data unless the client requests it.
|
145
|
+
true
|
146
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
147
|
+
# these "errors" indicate the connection is still usable
|
148
|
+
false
|
149
|
+
rescue => e
|
150
|
+
# other errors indicate the connection has a problem
|
151
|
+
true
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
86
155
|
def ensure_finished
|
87
156
|
@connection.finish if @connection && @connection.started?
|
88
157
|
@connection = nil
|
@@ -163,8 +163,8 @@ module ControllerActions
|
|
163
163
|
#
|
164
164
|
def deliver_file
|
165
165
|
if binary = @obj.binary
|
166
|
-
|
167
|
-
redirect_to
|
166
|
+
binary_routing = BinaryRouting.new(request, scrivito_engine)
|
167
|
+
redirect_to binary_routing.resolved_binary_obj_url(@obj, binary)
|
168
168
|
else
|
169
169
|
render text: 'Empty Blob', status: 404
|
170
170
|
end
|
@@ -20,7 +20,7 @@ module Scrivito
|
|
20
20
|
# @note +scrivito_path+ is also a helper method.
|
21
21
|
#
|
22
22
|
def scrivito_path(target, options = {})
|
23
|
-
CmsRouting.new(request,
|
23
|
+
CmsRouting.new(request, self, scrivito_engine).path_or_url(target, "path", options)
|
24
24
|
end
|
25
25
|
|
26
26
|
#
|
@@ -38,7 +38,7 @@ module Scrivito
|
|
38
38
|
# @note +scrivito_url+ is also a helper method.
|
39
39
|
#
|
40
40
|
def scrivito_url(target, options = {})
|
41
|
-
CmsRouting.new(request,
|
41
|
+
CmsRouting.new(request, self, scrivito_engine).path_or_url(target, "url", options)
|
42
42
|
end
|
43
43
|
|
44
44
|
#
|
@@ -17,7 +17,10 @@ module Scrivito
|
|
17
17
|
|
18
18
|
DateTime.iso8601(iso8601_date_time).in_time_zone
|
19
19
|
rescue ArgumentError
|
20
|
-
raise
|
20
|
+
raise Scrivito::ClientError.new(
|
21
|
+
"The value is not a valid ISO 8601 date time: #{iso8601_date_time.inspect}",
|
22
|
+
400
|
23
|
+
)
|
21
24
|
end
|
22
25
|
|
23
26
|
def self.serialize_for_backend(attribute_value)
|
data/lib/scrivito/deprecation.rb
CHANGED
@@ -5,14 +5,15 @@ module Scrivito
|
|
5
5
|
ActiveSupport::Deprecation.warn(message, source)
|
6
6
|
end
|
7
7
|
|
8
|
-
def warn_method(
|
9
|
-
warn(warn_method_message(
|
8
|
+
def warn_method(deprecated_method_name, new_method_name = nil)
|
9
|
+
warn(warn_method_message(deprecated_method_name, new_method_name), caller(1))
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
-
def warn_method_message(
|
15
|
-
message = "The method #{
|
14
|
+
def warn_method_message(deprecated_method_name, new_method_name = nil)
|
15
|
+
message = "The method #{deprecated_method_name} is deprecated and will be removed "\
|
16
|
+
"from the Scrivito SDK in the next major version. "
|
16
17
|
message << "Please use #{new_method_name} instead" if new_method_name
|
17
18
|
message
|
18
19
|
end
|
data/lib/scrivito/errors.rb
CHANGED
@@ -4,8 +4,25 @@ module Scrivito
|
|
4
4
|
class ScrivitoError < StandardError
|
5
5
|
end
|
6
6
|
|
7
|
+
class ApplicationError < ScrivitoError
|
8
|
+
def http_code
|
9
|
+
412
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_json
|
13
|
+
{message: message, message_for_editor: message}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
7
17
|
# @api public
|
8
18
|
class ResourceNotFound < ScrivitoError
|
19
|
+
def http_code
|
20
|
+
404
|
21
|
+
end
|
22
|
+
|
23
|
+
def as_json
|
24
|
+
{message: message}
|
25
|
+
end
|
9
26
|
end
|
10
27
|
|
11
28
|
# @api public
|
data/lib/scrivito/image_tag.rb
CHANGED
@@ -37,13 +37,13 @@ class ImageTag < Struct.new(:view_context)
|
|
37
37
|
BinaryRouting.new(request, scrivito_engine)
|
38
38
|
.binary_obj_url(obj_or_widget, attribute_value, image_options)
|
39
39
|
else
|
40
|
-
path = CmsRouting.new(request,
|
40
|
+
path = CmsRouting.new(request, view_context, scrivito_engine, image_options)
|
41
41
|
.path_or_url(attribute_value, :path)
|
42
42
|
path unless path == CmsRouting::LINK_TO_EMPTY_BLOB
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
delegate :request, :
|
46
|
+
delegate :request, :scrivito_engine, to: :view_context
|
47
47
|
end
|
48
48
|
|
49
49
|
end
|
data/lib/scrivito/link_parser.rb
CHANGED
@@ -63,9 +63,9 @@ module Scrivito
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def find_obj(uri)
|
66
|
-
return nil unless application_uri?(uri)
|
66
|
+
return nil unless application_uri?(uri)
|
67
67
|
|
68
|
-
route_params =
|
68
|
+
route_params = obj_route_params(uri)
|
69
69
|
|
70
70
|
if id = route_params[:id]
|
71
71
|
Obj.find(id)
|
@@ -75,9 +75,14 @@ module Scrivito
|
|
75
75
|
rescue Scrivito::ResourceNotFound
|
76
76
|
end
|
77
77
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
78
|
+
def obj_route_params(uri)
|
79
|
+
dispatch_route_for(sdk_route(uri)) || dispatch_route_for(route(uri)) || {}
|
80
|
+
end
|
81
|
+
|
82
|
+
def dispatch_route_for(route_params)
|
83
|
+
if route_params && route_params[:controller] == 'scrivito/cms_dispatch'
|
84
|
+
route_params
|
85
|
+
end
|
81
86
|
end
|
82
87
|
|
83
88
|
def sdk_route(uri)
|
@@ -38,6 +38,17 @@ module Scrivito
|
|
38
38
|
# [+iptc_state+] The state in which the image was produced.
|
39
39
|
# [+iptc_country_name+] The country in which the image was produced.
|
40
40
|
# [+iptc_country_code+] The code of the country in which the image was produced.
|
41
|
+
#
|
42
|
+
# == Searching for meta data
|
43
|
+
#
|
44
|
+
# Meta data is taken into account when searching. See the
|
45
|
+
# {Scrivito::ObjSearchEnumerator ObjSearchEnumerator} for details.
|
46
|
+
#
|
47
|
+
# @example Search for all JPEGs
|
48
|
+
# Image.where('blob:content_type', :equals, 'image/jpeg')
|
49
|
+
#
|
50
|
+
# @example Search for wide images
|
51
|
+
# Image.where('blob:width', :is_greater_than, 1024)
|
41
52
|
class MetaDataCollection
|
42
53
|
def initialize(attributes)
|
43
54
|
@attributes = ActiveSupport::HashWithIndifferentAccess.new(attributes)
|
@@ -85,7 +85,7 @@ module Scrivito
|
|
85
85
|
# @return [ObjSearchEnumerator]
|
86
86
|
# @api public
|
87
87
|
def all
|
88
|
-
ObjSearchEnumerator.new(workspace
|
88
|
+
ObjSearchEnumerator.new(workspace, 1000)
|
89
89
|
end
|
90
90
|
|
91
91
|
# Returns an {ObjSearchEnumerator} of all {BasicObj Obj}s with the given +obj_class+.
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Scrivito
|
2
|
+
#
|
2
3
|
# Instances of this class represent the result of a faceted search.
|
3
|
-
#
|
4
|
+
#
|
5
|
+
# @api public
|
6
|
+
#
|
4
7
|
class ObjFacetValue
|
5
8
|
|
6
9
|
def initialize(value, total, included_objs = [])
|
@@ -9,32 +12,41 @@ module Scrivito
|
|
9
12
|
@included_objs = included_objs
|
10
13
|
end
|
11
14
|
|
12
|
-
#
|
15
|
+
#
|
13
16
|
# The value of the attribute name of this ObjFacetValue.
|
14
17
|
#
|
18
|
+
# @api public
|
15
19
|
# @return [String]
|
20
|
+
#
|
16
21
|
def name
|
17
22
|
@name
|
18
23
|
end
|
19
24
|
|
20
|
-
#
|
25
|
+
#
|
21
26
|
# Total number of Objs available that have this value.
|
22
27
|
#
|
23
|
-
#
|
24
|
-
#
|
28
|
+
# @api public
|
29
|
+
#
|
30
|
+
# Note that this refers to all Objs, not just the Objs included in this search.
|
25
31
|
# Also note that the count is approximate.
|
32
|
+
#
|
26
33
|
# @return [Integer]
|
34
|
+
#
|
27
35
|
def count
|
28
36
|
@count
|
29
37
|
end
|
30
38
|
|
31
|
-
#
|
39
|
+
#
|
32
40
|
# The Objs that were included in this search.
|
33
41
|
#
|
34
|
-
#
|
42
|
+
# @api public
|
43
|
+
#
|
44
|
+
# If you did not specify +include_objs+ in your facet options,
|
35
45
|
# an empty array is returned.
|
36
46
|
# The Objs are ordered by relevance.
|
47
|
+
#
|
37
48
|
# @return [Array<BasicObj>]
|
49
|
+
#
|
38
50
|
def included_objs
|
39
51
|
@included_objs
|
40
52
|
end
|
@@ -28,26 +28,55 @@ module Scrivito
|
|
28
28
|
def parse_widgetlist_params(params)
|
29
29
|
params.map do |widget_id_or_params|
|
30
30
|
if widget_id_or_params.is_a?(Hash)
|
31
|
-
|
32
|
-
case action
|
33
|
-
when 'create' then Widget.new(widget_params, context.slice(:scrivito_user))
|
34
|
-
when 'copy'
|
35
|
-
widget_id = widget_params['widget_id']
|
36
|
-
widget = Workspace.find(widget_params['workspace_id'])
|
37
|
-
.objs.find(widget_params['obj_id'])
|
38
|
-
.widgets[widget_id]
|
39
|
-
raise ResourceNotFound, "Could not find Widget with id #{widget_id}" unless widget
|
40
|
-
widget.copy
|
41
|
-
else raise UnknownWidgetAction
|
42
|
-
end
|
31
|
+
parse_widgetlist_params_with_action(widget_id_or_params)
|
43
32
|
else
|
44
|
-
obj.widgets[widget_id_or_params]
|
33
|
+
widget = obj.widgets[widget_id_or_params]
|
34
|
+
raise_widget_not_found_error(widget_id_or_params) unless widget
|
35
|
+
widget
|
45
36
|
end
|
46
37
|
end
|
47
38
|
end
|
48
39
|
|
40
|
+
def parse_widgetlist_params_with_action(params)
|
41
|
+
action, widget_params = params.flatten
|
42
|
+
case action
|
43
|
+
when 'create' then Widget.new(widget_params, context.slice(:scrivito_user))
|
44
|
+
when 'copy'
|
45
|
+
widget_id = widget_params['widget_id']
|
46
|
+
widget = Workspace.find(widget_params['workspace_id'])
|
47
|
+
.objs.find(widget_params['obj_id'])
|
48
|
+
.widgets[widget_id]
|
49
|
+
raise_widget_not_found_error(widget_id) unless widget
|
50
|
+
widget.copy
|
51
|
+
else raise UnknownWidgetAction
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
49
55
|
def parse_binary_params(params)
|
50
|
-
|
56
|
+
return unless params
|
57
|
+
|
58
|
+
if params[:copy]
|
59
|
+
parse_copy_binary_params(params[:copy])
|
60
|
+
else
|
61
|
+
UploadedBinary.new(params)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_copy_binary_params(params)
|
66
|
+
obj = Obj.find(params[:obj_id])
|
67
|
+
|
68
|
+
if widget_id = params[:widget_id]
|
69
|
+
widget = obj.widgets[widget_id]
|
70
|
+
raise_widget_not_found_error(widget_id) unless widget
|
71
|
+
end
|
72
|
+
|
73
|
+
if binary = (widget || obj)[params[:attribute_name]]
|
74
|
+
binary.copy(filename: params[:filename], content_type: params[:content_type])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def raise_widget_not_found_error(widget_id)
|
79
|
+
raise ResourceNotFound, "Could not find Widget with id #{widget_id}"
|
51
80
|
end
|
52
81
|
end
|
53
82
|
end
|
@@ -40,8 +40,7 @@ class ObjSearchBuilder < Struct.new(:query)
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def set_order
|
43
|
-
enumerator.order(query[:order]) if query[:order]
|
44
|
-
enumerator.reverse_order if query[:reverse_order]
|
43
|
+
enumerator.order(Hash[*query[:order]]) if query[:order]
|
45
44
|
end
|
46
45
|
|
47
46
|
def set_batch_size
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Scrivito
|
2
|
+
class ObjSearchEnumerator
|
3
|
+
class Batch
|
4
|
+
def initialize(objs, total, continuation, facets, previously_fetched_ids)
|
5
|
+
@objs = filter_duplicates(objs, previously_fetched_ids)
|
6
|
+
@total = total
|
7
|
+
@continuation = continuation
|
8
|
+
@facets = facets
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :objs, :total, :continuation, :facets
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def filter_duplicates(objs, previously_fetched_ids)
|
16
|
+
objs.reject do |obj|
|
17
|
+
previously_fetched_ids.include?(obj.id)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Scrivito
|
2
|
+
class ObjSearchEnumerator
|
3
|
+
class BatchIterator
|
4
|
+
def initialize(workspace, query, initial_batch)
|
5
|
+
@query = query
|
6
|
+
@executor = ObjSearchEnumerator::QueryExecutor.new(workspace)
|
7
|
+
@all_fetched_ids = Set.new
|
8
|
+
@initial_batch = initial_batch
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :total
|
12
|
+
|
13
|
+
def each
|
14
|
+
current_batch = initial_batch || fetch_batch
|
15
|
+
|
16
|
+
loop do
|
17
|
+
yield current_batch
|
18
|
+
break unless current_batch.continuation
|
19
|
+
current_batch = fetch_batch(current_batch.continuation)
|
20
|
+
end
|
21
|
+
|
22
|
+
@total = @all_fetched_ids.size
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :query, :executor, :initial_batch
|
28
|
+
|
29
|
+
def fetch_batch(continuation=nil)
|
30
|
+
batch = executor.call(query, continuation, @all_fetched_ids)
|
31
|
+
@all_fetched_ids += batch.objs.map(&:id)
|
32
|
+
batch
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Scrivito
|
2
|
+
class ObjSearchEnumerator
|
3
|
+
class QueryExecutor
|
4
|
+
def initialize(workspace)
|
5
|
+
@workspace = workspace
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(query, continuation=nil, fetched_ids=[])
|
9
|
+
query['continuation'] = continuation if continuation
|
10
|
+
response = CmsBackend.instance.search_objs(workspace, query)
|
11
|
+
|
12
|
+
ObjSearchEnumerator::Batch.new(
|
13
|
+
build_objs(response),
|
14
|
+
response['total'].to_i,
|
15
|
+
response['continuation'],
|
16
|
+
response['facets'],
|
17
|
+
fetched_ids
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :workspace
|
24
|
+
|
25
|
+
def build_objs(response)
|
26
|
+
obj_ids = response['results'].map { |result| result['id'] }
|
27
|
+
if obj_ids.present?
|
28
|
+
workspace.objs.find_including_deleted(obj_ids)
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|