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
@@ -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
|