scrivito_sdk 0.66.0 → 0.70.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/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
|