scrivito_sdk 0.66.0 → 0.70.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/scrivito/blobs_controller.rb +5 -0
- data/app/controllers/scrivito/objs_controller.rb +2 -1
- data/app/controllers/scrivito/ui_controller.rb +33 -3
- data/app/helpers/scrivito_helper.rb +14 -20
- data/app/views/scrivito/objs/update.json.jbuilder +1 -1
- data/app/views/scrivito/ui/index.html.erb +1 -1
- data/app/views/scrivito/webservice/_workspace.json.jbuilder +2 -1
- data/config/ca-bundle.crt +1 -1
- data/config/precedence_routes.rb +3 -2
- data/lib/assets/javascripts/scrivito.js +46 -0
- data/lib/assets/javascripts/scrivito_ui.js +931 -501
- data/lib/assets/stylesheets/scrivito.css +1 -0
- data/lib/assets/stylesheets/scrivito_ui.css +1 -1
- data/lib/generators/scrivito/install/templates/app/views/page/index.html.erb +3 -3
- data/lib/generators/scrivito/page/page_generator.rb +3 -0
- data/lib/generators/scrivito/page/templates/model.erb +3 -0
- data/lib/generators/scrivito/widget/templates/model.erb +3 -0
- data/lib/generators/scrivito/widget/widget_generator.rb +3 -0
- data/lib/scrivito/attribute_content.rb +93 -60
- data/lib/scrivito/attribute_definition.rb +3 -3
- data/lib/scrivito/attribute_serializer.rb +2 -2
- data/lib/scrivito/backend/obj_data_cache.rb +22 -9
- data/lib/scrivito/basic_obj.rb +238 -130
- data/lib/scrivito/basic_widget.rb +32 -20
- data/lib/scrivito/binary.rb +74 -45
- data/lib/scrivito/binary_routing.rb +52 -0
- data/lib/scrivito/cache_middleware.rb +0 -5
- data/lib/scrivito/client_attribute_serializer.rb +134 -0
- data/lib/scrivito/cms_backend.rb +51 -33
- data/lib/scrivito/cms_data_cache.rb +1 -0
- data/lib/scrivito/cms_dispatch_controller.rb +1 -1
- data/lib/scrivito/cms_env.rb +1 -11
- data/lib/scrivito/cms_field_tag.rb +10 -7
- data/lib/scrivito/cms_rest_api/rate_limit.rb +5 -5
- data/lib/scrivito/cms_rest_api/request_timer.rb +27 -0
- data/lib/scrivito/cms_rest_api/widget_extractor.rb +8 -6
- data/lib/scrivito/cms_rest_api.rb +107 -54
- data/lib/scrivito/cms_routing.rb +13 -25
- data/lib/scrivito/configuration.rb +5 -2
- data/lib/scrivito/controller_actions.rb +68 -7
- data/lib/scrivito/controller_runtime.rb +8 -0
- data/lib/scrivito/date_attribute.rb +8 -0
- data/lib/scrivito/errors.rb +6 -3
- data/lib/scrivito/generator_helper.rb +13 -0
- data/lib/scrivito/image_tag.rb +24 -30
- data/lib/scrivito/layout_tags.rb +12 -6
- data/lib/scrivito/link.rb +46 -30
- data/lib/scrivito/log_subscriber.rb +15 -0
- data/lib/scrivito/membership.rb +3 -3
- data/lib/scrivito/membership_collection.rb +10 -10
- data/lib/scrivito/meta_data_collection.rb +22 -0
- data/lib/scrivito/model_library.rb +7 -1
- data/lib/scrivito/obj_collection.rb +18 -16
- data/lib/scrivito/obj_params_parser.rb +1 -1
- data/lib/scrivito/obj_search_enumerator.rb +35 -35
- data/lib/scrivito/page_config.rb +55 -0
- data/lib/scrivito/request_homepage.rb +23 -0
- data/lib/scrivito/routing_helper.rb +8 -8
- data/lib/scrivito/sdk_engine.rb +2 -3
- data/lib/scrivito/ui_config.rb +85 -0
- data/lib/scrivito/user.rb +30 -23
- data/lib/scrivito/user_definition.rb +48 -47
- data/lib/scrivito/widget_tag.rb +11 -0
- data/lib/scrivito/workspace.rb +93 -35
- data/lib/scrivito/workspace_selection_middleware.rb +8 -1
- data/lib/scrivito_sdk.rb +24 -24
- metadata +24 -33
- data/lib/assets/javascripts/scrivito_sdk.js +0 -57
- data/lib/assets/stylesheets/scrivito_sdk.css +0 -1
- data/lib/scrivito/client_config.rb +0 -113
- data/lib/scrivito/editing_context_helper.rb +0 -19
- data/lib/scrivito/named_link.rb +0 -39
data/lib/scrivito/cms_backend.rb
CHANGED
@@ -60,6 +60,7 @@ module Scrivito
|
|
60
60
|
def initialize
|
61
61
|
@query_counter = 0
|
62
62
|
@caching = true
|
63
|
+
@die_content_service = true
|
63
64
|
end
|
64
65
|
|
65
66
|
def begin_caching
|
@@ -88,7 +89,25 @@ module Scrivito
|
|
88
89
|
@query_counter = 0
|
89
90
|
end
|
90
91
|
|
91
|
-
def
|
92
|
+
def find_workspace_data_from_cache(id)
|
93
|
+
if die_content_service
|
94
|
+
cached_workspace_state = CmsDataCache.read_workspace_state(id)
|
95
|
+
cached_data_tag = cached_workspace_state.try(:second)
|
96
|
+
cached_content_state_id = cached_workspace_state.try(:first)
|
97
|
+
|
98
|
+
if cached_data_tag && cached_content_state_id
|
99
|
+
if raw_workspace_data = fetch_cached_data_by_tag(cached_data_tag)
|
100
|
+
build_workspace_data(raw_workspace_data, cached_content_state_id)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
else
|
104
|
+
WorkspaceDataFromService.find_from_cache(id)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def find_workspace_data_by_id(id, timeout=nil)
|
109
|
+
options = timeout ? {timeout: timeout} : {}
|
110
|
+
|
92
111
|
if die_content_service
|
93
112
|
begin
|
94
113
|
cached_workspace_state = CmsDataCache.read_workspace_state(id)
|
@@ -96,12 +115,12 @@ module Scrivito
|
|
96
115
|
cached_csid = cached_workspace_state.try(:first)
|
97
116
|
cached_workspace_data_tag = cached_workspace_state.try(:second)
|
98
117
|
|
99
|
-
changes = CmsRestApi.get("/workspaces/#{id}/changes", from: cached_csid)
|
118
|
+
changes = CmsRestApi.get("/workspaces/#{id}/changes", {from: cached_csid}, options)
|
100
119
|
|
101
120
|
update_obj_cache(id, cached_csid, changes)
|
102
121
|
|
103
|
-
|
104
|
-
id, cached_workspace_data_tag, changes["workspace"])
|
122
|
+
raw_workspace_data, workspace_data_tag = update_workspace_cache(
|
123
|
+
id, cached_workspace_data_tag, changes["workspace"], options)
|
105
124
|
|
106
125
|
current_csid = changes["current"]
|
107
126
|
current_workspace_state = [current_csid, workspace_data_tag]
|
@@ -110,8 +129,7 @@ module Scrivito
|
|
110
129
|
CmsDataCache.write_workspace_state(id, current_workspace_state)
|
111
130
|
end
|
112
131
|
|
113
|
-
return
|
114
|
-
"content_state_id" => current_csid))
|
132
|
+
return build_workspace_data(raw_workspace_data, current_csid)
|
115
133
|
|
116
134
|
rescue Scrivito::ClientError => client_error
|
117
135
|
if client_error.http_code == 404
|
@@ -122,22 +140,13 @@ module Scrivito
|
|
122
140
|
end
|
123
141
|
end
|
124
142
|
|
125
|
-
workspace_data_from_cache =
|
143
|
+
workspace_data_from_cache = find_workspace_data_from_cache(id)
|
126
144
|
from_content_state_id = workspace_data_from_cache.try(:content_state_id)
|
127
145
|
|
128
146
|
request_params = {:workspace_id => id}
|
129
147
|
request_params[:content_state_id] = from_content_state_id if from_content_state_id
|
130
148
|
|
131
|
-
raw_data =
|
132
|
-
begin
|
133
|
-
ContentService.query('workspaces/query', request_params, timeout: 1)
|
134
|
-
rescue CommunicationError => e
|
135
|
-
warn_backend_not_available(id, from_content_state_id, e.message)
|
136
|
-
return workspace_data_from_cache
|
137
|
-
end
|
138
|
-
else
|
139
|
-
ContentService.query('workspaces/query', request_params)
|
140
|
-
end
|
149
|
+
raw_data = ContentService.query('workspaces/query', request_params, options)
|
141
150
|
|
142
151
|
if raw_workspace_data = raw_data['workspace']
|
143
152
|
workspace_data = WorkspaceDataFromService.new(raw_workspace_data)
|
@@ -200,6 +209,18 @@ module Scrivito
|
|
200
209
|
end
|
201
210
|
end
|
202
211
|
|
212
|
+
def find_binary_meta_data(blob_id)
|
213
|
+
blob_id = normalize_blob_id(blob_id)
|
214
|
+
cache_key = "binary_meta_data/#{blob_id}"
|
215
|
+
if meta_data = CmsDataCache.cache.read(cache_key)
|
216
|
+
meta_data
|
217
|
+
else
|
218
|
+
meta_data = CmsRestApi.get("blobs/#{blob_id}/meta_data")['meta_data']
|
219
|
+
CmsDataCache.cache.write(cache_key, meta_data)
|
220
|
+
meta_data
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
203
224
|
def search_objs(workspace, params)
|
204
225
|
cache_index = 'search'
|
205
226
|
cache_key = params.to_param
|
@@ -213,7 +234,7 @@ module Scrivito
|
|
213
234
|
|
214
235
|
result = request_search_result_from_backend(workspace, params)
|
215
236
|
|
216
|
-
cache.
|
237
|
+
cache.write_index_not_updatable(cache_index, cache_key, result)
|
217
238
|
|
218
239
|
return result
|
219
240
|
end
|
@@ -231,17 +252,15 @@ module Scrivito
|
|
231
252
|
|
232
253
|
private
|
233
254
|
|
234
|
-
def update_workspace_cache(id, cached_data_tag, changed_workspace)
|
255
|
+
def update_workspace_cache(id, cached_data_tag, changed_workspace, options)
|
235
256
|
if changed_workspace
|
236
257
|
workspace_data = changed_workspace
|
237
258
|
else
|
238
|
-
cached_workspace_data =
|
239
|
-
|
240
|
-
if cached_workspace_data
|
259
|
+
if cached_workspace_data = fetch_cached_data_by_tag(cached_data_tag)
|
241
260
|
workspace_data = cached_workspace_data
|
242
261
|
workspace_data_tag = cached_data_tag
|
243
262
|
else
|
244
|
-
workspace_data = CmsRestApi.get("/workspaces/#{id}")
|
263
|
+
workspace_data = CmsRestApi.get("/workspaces/#{id}", nil, options)
|
245
264
|
end
|
246
265
|
end
|
247
266
|
|
@@ -250,6 +269,14 @@ module Scrivito
|
|
250
269
|
[workspace_data, workspace_data_tag]
|
251
270
|
end
|
252
271
|
|
272
|
+
def fetch_cached_data_by_tag(data_tag)
|
273
|
+
data_tag && CmsDataCache.read_data_from_tag(data_tag)
|
274
|
+
end
|
275
|
+
|
276
|
+
def build_workspace_data(raw_data, content_state_id)
|
277
|
+
WorkspaceData.new(raw_data.merge('content_state_id' => content_state_id))
|
278
|
+
end
|
279
|
+
|
253
280
|
def update_obj_cache(workspace_id, cached_csid, changes)
|
254
281
|
objs = changes["objs"]
|
255
282
|
if objs.present? && objs != "*"
|
@@ -302,7 +329,7 @@ module Scrivito
|
|
302
329
|
end
|
303
330
|
|
304
331
|
def normalize_blob_id(id)
|
305
|
-
|
332
|
+
CmsRestApi.normalize_path_component(id)
|
306
333
|
end
|
307
334
|
|
308
335
|
def fetch_blob_metadata_from_cache(id)
|
@@ -422,15 +449,6 @@ module Scrivito
|
|
422
449
|
raise ArgumentError, "invalid index name '#{index}'" unless VALID_INDEX_NAMES.include?(index)
|
423
450
|
end
|
424
451
|
|
425
|
-
def warn_backend_not_available(workspace_id, content_state_id, error_message)
|
426
|
-
message = <<-EOS
|
427
|
-
Couldn't connect to content service for workspace with id=#{workspace_id} and content_state_id=#{content_state_id}.
|
428
|
-
#{error_message}
|
429
|
-
Serving from cache.
|
430
|
-
EOS
|
431
|
-
Rails.logger.warn(message)
|
432
|
-
end
|
433
|
-
|
434
452
|
end
|
435
453
|
|
436
454
|
end
|
data/lib/scrivito/cms_env.rb
CHANGED
@@ -33,17 +33,7 @@ module Scrivito
|
|
33
33
|
elsif params[:permalink].present?
|
34
34
|
self.class.find_permalink_by_param(params[:permalink])
|
35
35
|
else
|
36
|
-
|
37
|
-
callback_result = callback.call(env)
|
38
|
-
if callback_result.is_a?(Obj)
|
39
|
-
callback_result
|
40
|
-
else
|
41
|
-
raise "choose_homepage callback did not return an Obj. "\
|
42
|
-
"Instead saw #{callback_result.class}."
|
43
|
-
end
|
44
|
-
else
|
45
|
-
Obj.homepage
|
46
|
-
end
|
36
|
+
Scrivito::RequestHomepage.call(env)
|
47
37
|
end
|
48
38
|
|
49
39
|
found_obj
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Scrivito
|
2
2
|
|
3
|
-
#
|
3
|
+
# This class is the server-side equivalent of the JavaScript +cms_field_element+ class.
|
4
4
|
class CmsFieldTag < Struct.new(:view, :tag_name, :obj_or_widget, :editing_options)
|
5
5
|
FIELD_TYPES_WITH_ORIGINAL_CONTENT = %w[
|
6
6
|
binary
|
@@ -135,12 +135,15 @@ class CmsFieldTag < Struct.new(:view, :tag_name, :obj_or_widget, :editing_option
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def original_content(field_type, field_value, raw_value)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
138
|
+
if %w[
|
139
|
+
binary
|
140
|
+
date
|
141
|
+
reference
|
142
|
+
referencelist
|
143
|
+
].include?(field_type)
|
144
|
+
ClientAttributeSerializer.serialize_custom_attr_value(field_type, raw_value)
|
145
|
+
else
|
146
|
+
ClientAttributeSerializer.serialize_custom_attr_value(field_type, field_value)
|
144
147
|
end
|
145
148
|
end
|
146
149
|
|
@@ -2,21 +2,21 @@ module Scrivito
|
|
2
2
|
class CmsRestApi
|
3
3
|
module RateLimit
|
4
4
|
class << self
|
5
|
-
def retry_on_rate_limit(
|
6
|
-
internal_retry(block,
|
5
|
+
def retry_on_rate_limit(request_timer, &block)
|
6
|
+
internal_retry(block, request_timer, 0)
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
def internal_retry(request_proc,
|
11
|
+
def internal_retry(request_proc, request_timer, retry_count)
|
12
12
|
response = request_proc.call
|
13
13
|
|
14
14
|
if failed_because_of_rate_limit?(response)
|
15
15
|
time_to_sleep = calculate_time_to_sleep(response['Retry-After'].to_f, retry_count)
|
16
16
|
|
17
|
-
if (Time.now + time_to_sleep.seconds)
|
17
|
+
if request_timer.cover?(Time.now + time_to_sleep.seconds)
|
18
18
|
sleep time_to_sleep
|
19
|
-
internal_retry(request_proc,
|
19
|
+
internal_retry(request_proc, request_timer, retry_count + 1)
|
20
20
|
else
|
21
21
|
raise Scrivito::RateLimitExceeded.new('rate limit exceeded', 429)
|
22
22
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Scrivito
|
2
|
+
class CmsRestApi
|
3
|
+
class RequestTimer
|
4
|
+
MIN_REQUEST_TIME = 0.005
|
5
|
+
|
6
|
+
def initialize(max_duration)
|
7
|
+
@finish_before = Time.now + max_duration
|
8
|
+
end
|
9
|
+
|
10
|
+
def finished?
|
11
|
+
remaining_time <= MIN_REQUEST_TIME
|
12
|
+
end
|
13
|
+
|
14
|
+
def remaining_time
|
15
|
+
[finish_before - Time.now, 0].max
|
16
|
+
end
|
17
|
+
|
18
|
+
def cover?(point_in_time)
|
19
|
+
point_in_time <= finish_before
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :finish_before
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -2,9 +2,11 @@ module Scrivito
|
|
2
2
|
class CmsRestApi
|
3
3
|
class WidgetExtractor
|
4
4
|
|
5
|
-
# Extract widgets from a given attribute tree
|
6
|
-
# hash of widget_like =>
|
7
|
-
|
5
|
+
# Extract widgets from a given attribute tree
|
6
|
+
# first return param: a flat hash of widget_like => updated widget attributes
|
7
|
+
# second return param: the updated attributes
|
8
|
+
def self.call(attributes, obj=nil)
|
9
|
+
updated_attributes = attributes.dup
|
8
10
|
extracted_widgets = {}
|
9
11
|
|
10
12
|
(updated_attributes.delete(:_widget_pool) || {}).each do |widget, widget_properties|
|
@@ -12,7 +14,7 @@ module Scrivito
|
|
12
14
|
raise ScrivitoError, 'new top-level widgets are not allowed in the _widget_pool'
|
13
15
|
end
|
14
16
|
extracted_widgets[widget] = widget_properties
|
15
|
-
extracted_widgets.merge!(call(widget_properties, obj))
|
17
|
+
extracted_widgets.merge!(call(widget_properties, obj).first)
|
16
18
|
end
|
17
19
|
|
18
20
|
updated_attributes.each do |attribute_name, value|
|
@@ -21,13 +23,13 @@ module Scrivito
|
|
21
23
|
unless widget.persisted?
|
22
24
|
attach_widget_to_obj(widget, obj)
|
23
25
|
extracted_widgets[widget] = widget.attributes_to_be_saved
|
24
|
-
extracted_widgets.merge!(call(widget.attributes_to_be_saved, obj))
|
26
|
+
extracted_widgets.merge!(call(widget.attributes_to_be_saved, obj).first)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
extracted_widgets
|
32
|
+
return extracted_widgets, updated_attributes
|
31
33
|
end
|
32
34
|
|
33
35
|
def self.attach_widget_to_obj(widget, obj)
|
@@ -32,27 +32,28 @@ module Scrivito
|
|
32
32
|
:delete => Net::HTTP::Delete,
|
33
33
|
}.freeze
|
34
34
|
|
35
|
-
|
35
|
+
DEFAULT_TIMEOUT = 25.seconds.freeze
|
36
|
+
MAX_REQUEST_TIME = 10.seconds.freeze
|
36
37
|
|
37
|
-
def self.get(resource_path, payload = nil, options =
|
38
|
+
def self.get(resource_path, payload = nil, options = {})
|
38
39
|
request_cms_api(:get, resource_path, payload, options)
|
39
40
|
end
|
40
41
|
|
41
|
-
def self.put(resource_path, payload, options =
|
42
|
+
def self.put(resource_path, payload, options = {})
|
42
43
|
request_cms_api(:put, resource_path, payload, options)
|
43
44
|
end
|
44
45
|
|
45
|
-
def self.post(resource_path, payload, options =
|
46
|
+
def self.post(resource_path, payload, options = {})
|
46
47
|
request_cms_api(:post, resource_path, payload, options)
|
47
48
|
end
|
48
49
|
|
49
|
-
def self.delete(resource_path, payload = nil, options =
|
50
|
+
def self.delete(resource_path, payload = nil, options = {})
|
50
51
|
request_cms_api(:delete, resource_path, payload, options)
|
51
52
|
end
|
52
53
|
|
53
54
|
def self.task_unaware_request(method, resource_path, payload = nil)
|
54
55
|
raise "Unexpected method #{method}" unless [:delete, :get, :post, :put].include?(method)
|
55
|
-
response_for_request_cms_api(method, resource_path, payload)
|
56
|
+
response_for_request_cms_api(method, resource_path, payload, build_timer)
|
56
57
|
end
|
57
58
|
|
58
59
|
def self.count_requests(path)
|
@@ -63,21 +64,19 @@ module Scrivito
|
|
63
64
|
@number_of_requests
|
64
65
|
end
|
65
66
|
|
66
|
-
def self.upload_file(file)
|
67
|
+
def self.upload_file(file, obj_id)
|
67
68
|
upload_permission = get('blobs/upload_permission')
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
end
|
69
|
+
upload = perform_file_upload(file, upload_permission)
|
70
|
+
activate_upload(upload: upload, obj_id: obj_id)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.activate_upload(params)
|
74
|
+
put('blobs/activate_upload', params)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.normalize_path_component(component)
|
78
|
+
Addressable::URI.normalize_component(component,
|
79
|
+
Addressable::URI::CharacterClasses::UNRESERVED)
|
81
80
|
end
|
82
81
|
|
83
82
|
class << self
|
@@ -85,35 +84,47 @@ module Scrivito
|
|
85
84
|
private
|
86
85
|
|
87
86
|
def request_cms_api(action, resource_path, payload, options)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
87
|
+
log_api_request(action, resource_path, payload) do
|
88
|
+
@number_of_requests += 1 if resource_path == @count_requests
|
89
|
+
|
90
|
+
timer = build_timer(options)
|
91
|
+
response = response_for_request_cms_api(action, resource_path, payload, timer)
|
92
|
+
|
93
|
+
if task_response?(response)
|
94
|
+
task_path = "tasks/#{response['task']['id']}"
|
95
|
+
poll_interval = options[:interval].presence.try(:to_f) || 2
|
96
|
+
wait_for_tasks_final_response(task_path, poll_interval)
|
97
|
+
else
|
98
|
+
response
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def log_api_request(action, resource_path, payload, &block)
|
104
|
+
ActiveSupport::Notifications.instrumenter.instrument(
|
105
|
+
"backend_request.scrivito",
|
106
|
+
{
|
107
|
+
:path => resource_path,
|
108
|
+
:verb => action,
|
109
|
+
:params => action == :get ? payload : nil
|
110
|
+
},
|
111
|
+
&block
|
112
|
+
)
|
96
113
|
end
|
97
114
|
|
98
|
-
def
|
115
|
+
def task_response?(response)
|
116
|
+
response.is_a?(Hash) && response.keys == ['task'] && response['task'].is_a?(Hash)
|
117
|
+
end
|
118
|
+
|
119
|
+
def response_for_request_cms_api(method, resource_path, payload, timer)
|
99
120
|
request = method_to_net_http_class(method).new(path(resource_path))
|
100
121
|
set_headers(request)
|
101
122
|
request.body = MultiJson.encode(payload) if payload.present?
|
102
123
|
|
103
|
-
response =
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
response = CmsRestApi::RateLimit.retry_on_rate_limit(wait_until) do
|
108
|
-
# lower timeout back to DEFAULT_TIMEOUT once the backend has been fixed
|
109
|
-
connection_manager.request(request, 25)
|
110
|
-
end
|
111
|
-
rescue NetworkError => e
|
112
|
-
if method == :post || retried
|
113
|
-
raise e
|
114
|
-
else
|
115
|
-
retried = true
|
116
|
-
retry
|
124
|
+
response = retry_once_on_network_error(method, timer) do
|
125
|
+
CmsRestApi::RateLimit.retry_on_rate_limit(timer) do
|
126
|
+
request_timeout = [timer.remaining_time, MAX_REQUEST_TIME].min
|
127
|
+
connection_manager.request(request, request_timeout)
|
117
128
|
end
|
118
129
|
end
|
119
130
|
|
@@ -146,19 +157,57 @@ module Scrivito
|
|
146
157
|
end
|
147
158
|
end
|
148
159
|
|
149
|
-
def
|
150
|
-
|
151
|
-
|
152
|
-
task_data
|
160
|
+
def wait_for_tasks_final_response(task_path, poll_interval)
|
161
|
+
task_data = fetch_final_response(task_path, poll_interval)
|
162
|
+
|
163
|
+
if task_data['status'] == 'success'
|
164
|
+
task_data['result']
|
165
|
+
else
|
166
|
+
message = task_data["message"] ||
|
167
|
+
"Missing error message in task response #{task_data}"
|
168
|
+
|
169
|
+
backend_code = task_data['code']
|
170
|
+
raise ClientError.new(message, 400, backend_code)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def perform_file_upload(file, upload_permission)
|
175
|
+
uri = URI.parse(upload_permission['url'])
|
176
|
+
File.open(file) do |open_file|
|
177
|
+
content_type = MIME::Types.type_for(file.path).first.content_type
|
178
|
+
upload_io = UploadIO.new(open_file, content_type, File.basename(file))
|
179
|
+
params = upload_permission['fields'].merge('file' => upload_io)
|
180
|
+
request = Net::HTTP::Post::Multipart.new(uri.path, params)
|
181
|
+
response = ConnectionManager.request(uri, request)
|
182
|
+
if response.code.starts_with?('2')
|
183
|
+
upload_permission['blob'].merge('filename' => File.basename(file.path))
|
184
|
+
else
|
185
|
+
raise ScrivitoError, "File upload failed with code #{response.code}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def fetch_final_response(task_path, poll_interval)
|
153
191
|
loop do
|
154
|
-
sleep
|
155
|
-
task_data = response_for_request_cms_api(:get, task_path, nil)
|
156
|
-
|
192
|
+
sleep poll_interval
|
193
|
+
task_data = response_for_request_cms_api(:get, task_path, nil, build_timer)
|
194
|
+
|
195
|
+
return task_data if task_data['status'] != 'open'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def retry_once_on_network_error(method, timer)
|
200
|
+
return yield if method == :post
|
201
|
+
|
202
|
+
begin
|
203
|
+
yield
|
204
|
+
rescue NetworkError => e
|
205
|
+
if timer.finished?
|
206
|
+
raise e
|
207
|
+
else
|
208
|
+
yield
|
209
|
+
end
|
157
210
|
end
|
158
|
-
return task_data["result"] if task_data["status"] == "success"
|
159
|
-
message = task_data["message"] || "Missing error message in task response #{task_data}"
|
160
|
-
backend_code = task_data['code']
|
161
|
-
raise ClientError.new(message, 400, backend_code)
|
162
211
|
end
|
163
212
|
|
164
213
|
def set_headers(request)
|
@@ -175,6 +224,10 @@ module Scrivito
|
|
175
224
|
ConnectionManager.instance
|
176
225
|
end
|
177
226
|
|
227
|
+
def build_timer(options={})
|
228
|
+
CmsRestApi::RequestTimer.new(options.fetch(:timeout, DEFAULT_TIMEOUT))
|
229
|
+
end
|
230
|
+
|
178
231
|
def method_to_net_http_class(method)
|
179
232
|
METHOD_TO_NET_HTTP_CLASS.fetch(method)
|
180
233
|
end
|
data/lib/scrivito/cms_routing.rb
CHANGED
@@ -18,7 +18,7 @@ class CmsRouting < Struct.new(:request, :main_app, :scrivito_engine, :image_opti
|
|
18
18
|
|
19
19
|
def convert_links(html)
|
20
20
|
if html
|
21
|
-
html.gsub(%r{\bobjid:([a-f0-9]{16})\b([^"']*)}) do
|
21
|
+
html.to_str.gsub(%r{\bobjid:([a-f0-9]{16})\b([^"']*)}) do
|
22
22
|
if obj = Obj.find_by_id($1)
|
23
23
|
options = {}
|
24
24
|
|
@@ -62,7 +62,7 @@ class CmsRouting < Struct.new(:request, :main_app, :scrivito_engine, :image_opti
|
|
62
62
|
return LINK_TO_EMPTY_LINKLIST
|
63
63
|
end
|
64
64
|
elsif target.is_a?(Binary)
|
65
|
-
binary_url(target
|
65
|
+
binary_url(target)
|
66
66
|
else
|
67
67
|
raise "scrivito_path or scrivito_url was called with an instance of #{target.class}. "+
|
68
68
|
"It must only be called with an Obj or a Link or a non-empty LinkList."
|
@@ -81,14 +81,10 @@ class CmsRouting < Struct.new(:request, :main_app, :scrivito_engine, :image_opti
|
|
81
81
|
if permalink
|
82
82
|
main_app
|
83
83
|
.public_send("scrivito_permalink_#{path_or_url}", options.merge(:permalink => permalink))
|
84
|
-
elsif
|
84
|
+
elsif homepage?(obj)
|
85
85
|
main_app.public_send("scrivito_root_#{path_or_url}", options)
|
86
86
|
elsif obj.binary?
|
87
|
-
|
88
|
-
binary_url(binary, path_or_url)
|
89
|
-
else
|
90
|
-
LINK_TO_EMPTY_BLOB
|
91
|
-
end
|
87
|
+
binary_obj_url(obj) || LINK_TO_EMPTY_BLOB
|
92
88
|
else
|
93
89
|
slug = obj.slug.present? ? obj.slug.sub(/^\//, '') : nil
|
94
90
|
id_path_or_url_for_objs(obj, path_or_url, options.merge(slug: slug))
|
@@ -105,6 +101,10 @@ class CmsRouting < Struct.new(:request, :main_app, :scrivito_engine, :image_opti
|
|
105
101
|
main_app.public_send(method_name, options.merge(id: obj.id))
|
106
102
|
end
|
107
103
|
|
104
|
+
def homepage?(obj)
|
105
|
+
RequestHomepage.call(request.env) == obj
|
106
|
+
end
|
107
|
+
|
108
108
|
def editor_authenticated?
|
109
109
|
editing_context.authenticated_editor?
|
110
110
|
end
|
@@ -141,27 +141,15 @@ class CmsRouting < Struct.new(:request, :main_app, :scrivito_engine, :image_opti
|
|
141
141
|
Rack::Utils.parse_query(uri.query)
|
142
142
|
end
|
143
143
|
|
144
|
-
def binary_url(binary
|
145
|
-
|
146
|
-
if url_from_cache = binary.url_from_cache
|
147
|
-
BinaryRewrite.call(request, url_from_cache)
|
148
|
-
else
|
149
|
-
encrypted_params = BinaryParamVerifier.generate(binary)
|
150
|
-
scrivito_engine.public_send("binary_#{path_or_url}", encrypted_params: encrypted_params)
|
151
|
-
end
|
144
|
+
def binary_url(binary)
|
145
|
+
BinaryRouting.new(request, scrivito_engine).binary_url(binary)
|
152
146
|
end
|
153
147
|
|
154
|
-
def
|
155
|
-
if
|
156
|
-
|
157
|
-
else
|
158
|
-
binary
|
148
|
+
def binary_obj_url(obj)
|
149
|
+
if binary = obj.binary
|
150
|
+
BinaryRouting.new(request, scrivito_engine).binary_obj_url(obj, binary, image_options || {})
|
159
151
|
end
|
160
152
|
end
|
161
|
-
|
162
|
-
def image_options
|
163
|
-
super || {}
|
164
|
-
end
|
165
153
|
end
|
166
154
|
|
167
155
|
end
|
@@ -208,6 +208,9 @@ module Scrivito
|
|
208
208
|
self.check_batch_size = 100
|
209
209
|
self.legacy_routing = false
|
210
210
|
self.default_image_transformation = {}
|
211
|
+
self.choose_homepage_callback = -> (env) { Obj.root }
|
212
|
+
self.find_user_proc = nil
|
213
|
+
reset_editing_auth_callback!
|
211
214
|
end
|
212
215
|
|
213
216
|
#
|
@@ -238,7 +241,7 @@ module Scrivito
|
|
238
241
|
#
|
239
242
|
# Set the default {Scrivito::Binary#transform image transformation}.
|
240
243
|
#
|
241
|
-
# @api
|
244
|
+
# @api public
|
242
245
|
#
|
243
246
|
# When delivering binary Objs, the default image transformation will be applied if
|
244
247
|
# {Scrivito::BasicObj#apply_image_transformation? Obj#apply_image_transformation?} returns
|
@@ -259,7 +262,7 @@ module Scrivito
|
|
259
262
|
# Configure a callback to be invoked when the Scrivito SDK delivers the homepage.
|
260
263
|
# The given callback will receive the rack env
|
261
264
|
# and must return an {BasicObj Obj} to be used as the homepage.
|
262
|
-
# If no callback is configured, {BasicObj.
|
265
|
+
# If no callback is configured, {BasicObj.root Obj.root} will be used as the default.
|
263
266
|
# @api public
|
264
267
|
def choose_homepage(&block)
|
265
268
|
self.choose_homepage_callback = block
|