scrivito_sdk 0.17.0 → 0.18.0
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/app/controllers/scrivito/default_cms_controller.rb +15 -3
- data/app/controllers/scrivito/objs_controller.rb +61 -25
- data/app/controllers/scrivito/users_controller.rb +7 -0
- data/app/controllers/scrivito/webservice_controller.rb +17 -7
- data/app/controllers/scrivito/workspaces_controller.rb +85 -17
- data/app/helpers/scrivito/default_cms_routing_helper.rb +3 -3
- data/config/routes.rb +4 -1
- data/lib/assets/javascripts/scrivito_editing.js +4182 -508
- data/lib/assets/stylesheets/scrivito_editing.css +489 -13
- data/lib/generators/cms/migration/templates/migration.erb +4 -4
- data/lib/scrivito/attribute_collection.rb +1 -6
- data/lib/scrivito/attribute_content.rb +29 -7
- data/lib/scrivito/basic_obj.rb +91 -61
- data/lib/scrivito/basic_widget.rb +0 -11
- data/lib/scrivito/client_config.rb +40 -25
- data/lib/scrivito/cms_backend.rb +54 -0
- data/lib/scrivito/cms_cache_storage.rb +8 -0
- data/lib/scrivito/cms_field_tag.rb +2 -1
- data/lib/scrivito/cms_rest_api.rb +9 -0
- data/lib/scrivito/configuration.rb +4 -2
- data/lib/scrivito/content_state.rb +8 -0
- data/lib/scrivito/content_state_caching.rb +20 -0
- data/lib/scrivito/editing_context.rb +35 -34
- data/lib/scrivito/membership.rb +22 -3
- data/lib/scrivito/memberships_collection.rb +8 -4
- data/lib/scrivito/obj_class.rb +45 -100
- data/lib/scrivito/obj_class_collection.rb +53 -0
- data/lib/scrivito/obj_class_data.rb +33 -0
- data/lib/scrivito/obj_data.rb +26 -48
- data/lib/scrivito/obj_data_from_hash.rb +5 -5
- data/lib/scrivito/obj_data_from_service.rb +9 -3
- data/lib/scrivito/obj_search_builder.rb +0 -5
- data/lib/scrivito/obj_search_enumerator.rb +3 -20
- data/lib/scrivito/objs_collection.rb +7 -0
- data/lib/scrivito/restriction_set.rb +2 -2
- data/lib/scrivito/user.rb +89 -23
- data/lib/scrivito/user_definition.rb +73 -70
- data/lib/scrivito/workspace.rb +52 -8
- data/lib/scrivito/workspace/publish_checker.rb +126 -0
- metadata +6 -2
@@ -1,63 +1,67 @@
|
|
1
1
|
module Scrivito
|
2
|
-
# @api
|
3
|
-
class UserDefinition
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# Allows user to do everything.
|
9
|
-
# @api beta
|
10
|
-
ADMINISTRATE_CMS_ABILITY = 'administrate_cms'
|
11
|
-
|
12
|
-
# @api beta
|
13
|
-
ABILITY_NAMES = [
|
14
|
-
ADMINISTRATE_CMS_ABILITY,
|
15
|
-
PUBLISH_WORKSPACE_ABILITY,
|
16
|
-
]
|
2
|
+
# @api public
|
3
|
+
class UserDefinition
|
4
|
+
def initialize(user_id)
|
5
|
+
@user_id = user_id
|
6
|
+
@explicit_rules = {}
|
7
|
+
end
|
17
8
|
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# @
|
21
|
-
# @param [
|
22
|
-
# @
|
23
|
-
# @
|
24
|
-
# @
|
25
|
-
# @
|
26
|
-
#
|
27
|
-
# @
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
9
|
+
# Adds an explicit rule, that allows the user to _always_ execute an action.
|
10
|
+
# A rule consists of a verb of the action, the subject of the action and an optional message.
|
11
|
+
# @api public
|
12
|
+
# @param [Symbol] verb the verb of the action (see {Scrivito::User::VERBS}).
|
13
|
+
# @param [Symbol] subject the subject of the action. At the moment only +:workspace+ is supported.
|
14
|
+
# @param [String] message optional message to be displayed in the UI.
|
15
|
+
# @raise [Scrivito::ScrivitoError] if the given verb is invalid
|
16
|
+
# @raise [Scrivito::ScrivitoError] if the specified rule conflicts with a rule specified with
|
17
|
+
# {Scrivito::UserDefinition#can_never}.
|
18
|
+
# @note Normally the memberships of a workspace decide whether a user is allowed or not to
|
19
|
+
# execute a specific action. This method allows to add an exception to this logic and thus
|
20
|
+
# should be used carefully.
|
21
|
+
# @see Scrivito::User::VERBS
|
22
|
+
# @see Scrivito::UserDefinition#can_never
|
23
|
+
# @example User can _always_ read, write and publish a workspace, ignoring the memberships.
|
24
|
+
# Scrivito::User.define('alice') do |user|
|
25
|
+
# user.can_always(:read, :workspace)
|
26
|
+
# user.can_always(:write, :workspace)
|
27
|
+
# user.can_always(:publish, :workspace, 'You can always publish a workspace.)
|
33
28
|
# end
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
def can_always(verb, subject, message = nil)
|
30
|
+
assert_no_conflict(:can_never, verb, subject)
|
31
|
+
@explicit_rules[[:can_always, verb, subject]] = message
|
32
|
+
end
|
33
|
+
|
34
|
+
# Adds an explicit rule, that forbids the user to execute an action.
|
35
|
+
# A rule consists of a verb of the action, the subject of the action and an optional message.
|
36
|
+
# @api public
|
37
|
+
# @param [Symbol] verb the verb of the action (see {Scrivito::User::VERBS}).
|
38
|
+
# @param [Symbol] subject the subject of the action. At the moment only +:workspace+ is supported.
|
39
|
+
# @param [String] message optional message to be displayed in the UI.
|
40
|
+
# @raise [Scrivito::ScrivitoError] if the given verb is invalid
|
41
|
+
# @raise [Scrivito::ScrivitoError] if the specified rule conflicts with a rule specified with
|
42
|
+
# {Scrivito::UserDefinition#can_always}.
|
43
|
+
# @note Normally the memberships of a workspace decide whether a user is allowed or not to
|
44
|
+
# execute a specific action. This method allows to add an exception to this logic and thus
|
45
|
+
# should be used carefully.
|
46
|
+
# @see Scrivito::User::VERBS
|
47
|
+
# @see Scrivito::UserDefinition#can_always
|
48
|
+
# @example User can _never_ publish a workspace, even if she's a workspace owner.
|
49
|
+
# Scrivito::User.define('alice') do |user|
|
50
|
+
# user.can_never(:publish, :workspace, 'You can not publish workspaces.')
|
37
51
|
# end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# allowed_user = 'alice'
|
42
|
-
# # The user `alice` will now be allowed to publish workspace,
|
43
|
-
# # but the user `bob` will still be not allowed.
|
44
|
-
#
|
45
|
-
# allowed_user = 'bob'
|
46
|
-
# # The user `bob` will now be allowed to publish workspace,
|
47
|
-
# # but the user `alice` will be not allowed again.
|
48
|
-
def can(ability_name, &ability_proc)
|
49
|
-
assert_valid_ability(ability_name, ability_proc)
|
50
|
-
abilities[ability_name] = ability_proc
|
52
|
+
def can_never(verb, subject, message = nil)
|
53
|
+
assert_no_conflict(:can_always, verb, subject)
|
54
|
+
@explicit_rules[[:can_never, verb, subject]] = message
|
51
55
|
end
|
52
56
|
|
53
57
|
# Defines the user description to be displayed, when the user is shown in the in-place GUI.
|
54
|
-
# @api
|
58
|
+
# @api public
|
55
59
|
# @param [Proc] description_proc proc to calculate the description. Defaults to the the user id.
|
56
60
|
# @note The description is calculated "lazy".
|
57
61
|
# @note The calculated description will be cached.
|
58
62
|
# @see Scrivito::User.define
|
59
63
|
# @example
|
60
|
-
# alice = Scrivito::User.define('alice')
|
64
|
+
# alice = Scrivito::User.define('alice')
|
61
65
|
# # User `alice` will be displayed as "alice" in the in-place GUI.
|
62
66
|
#
|
63
67
|
# bob = Scrivito::User.define('bob') do |user|
|
@@ -70,7 +74,9 @@ module Scrivito
|
|
70
74
|
|
71
75
|
# Defines the proc for fetching users for the user autocompletion of the in-place GUI.
|
72
76
|
# The user autocompletion is for example used in the details dialog of a workspace.
|
73
|
-
#
|
77
|
+
# If the proc is not set, then {Scrivito::User.find} will be used to fetch the suggested users with input
|
78
|
+
# as the user id.
|
79
|
+
# @api public
|
74
80
|
# @param [Proc] suggest_users_proc proc for fetching users to be suggested in the in-place GUI
|
75
81
|
# @yieldparam [String] input an arbitrary string from the input field of a user autocompletion,
|
76
82
|
# e.g. the first letters of a user name
|
@@ -91,25 +97,25 @@ module Scrivito
|
|
91
97
|
@suggest_users_proc = suggest_users_proc
|
92
98
|
end
|
93
99
|
|
94
|
-
# Lets you restrict the
|
100
|
+
# Lets you restrict the rule of a user to publish a certain object. Each
|
95
101
|
# registered callback can access a certain attribute of an object. Multiple
|
96
102
|
# callbacks are possible
|
97
103
|
#
|
98
|
-
# @api
|
104
|
+
# @api public
|
99
105
|
# @param [Hash] options
|
100
|
-
# @option options [Symbol] :
|
106
|
+
# @option options [Symbol] :using the attribute you need in the callback
|
101
107
|
# @yield [attribute] the value of the specified attribute
|
102
108
|
# @yieldreturn [String, false] either return a message for the user or false if
|
103
109
|
# no restriction is needed
|
104
110
|
#
|
105
111
|
# @note the callback is only called with {BasicObj Objs} that have the attribute
|
106
|
-
# specified by the :
|
112
|
+
# specified by the :using option and if it is not a {BasicWidget Widget}-attribute
|
107
113
|
#
|
108
114
|
# @example
|
109
115
|
# class MyUserModel
|
110
116
|
# def to_scrivito_user
|
111
117
|
# Scrivito::User.define(id) do |user|
|
112
|
-
# user.restrict_obj_publish(
|
118
|
+
# user.restrict_obj_publish(using: :_path) do |path|
|
113
119
|
# if path.start_with?("/en")
|
114
120
|
# false
|
115
121
|
# else
|
@@ -117,11 +123,11 @@ module Scrivito
|
|
117
123
|
# end
|
118
124
|
# end
|
119
125
|
#
|
120
|
-
# user.restrict_obj_publish(
|
121
|
-
# if obj_class ==
|
126
|
+
# user.restrict_obj_publish(using: :_obj_class) do |obj_class|
|
127
|
+
# if obj_class.name == 'BlogPost'
|
122
128
|
# false
|
123
129
|
# else
|
124
|
-
#
|
130
|
+
# 'You are only allowed to edit Blog Posts'
|
125
131
|
# end
|
126
132
|
# end
|
127
133
|
# end
|
@@ -132,8 +138,13 @@ module Scrivito
|
|
132
138
|
end
|
133
139
|
|
134
140
|
def user
|
135
|
-
User.new(
|
136
|
-
|
141
|
+
User.new(
|
142
|
+
id: @user_id,
|
143
|
+
explicit_rules: @explicit_rules,
|
144
|
+
description_proc: @description_proc,
|
145
|
+
suggest_users_proc: @suggest_users_proc,
|
146
|
+
restriction_set: restriction_set
|
147
|
+
)
|
137
148
|
end
|
138
149
|
|
139
150
|
private
|
@@ -142,17 +153,9 @@ module Scrivito
|
|
142
153
|
@restriction_set ||= RestrictionSet.new
|
143
154
|
end
|
144
155
|
|
145
|
-
def
|
146
|
-
@
|
147
|
-
|
148
|
-
|
149
|
-
def assert_valid_ability(ability_name, ability_proc)
|
150
|
-
unless ABILITY_NAMES.include?(ability_name.to_s)
|
151
|
-
raise ScrivitoError.new("'#{ability_name}' is not a valid ability name")
|
152
|
-
end
|
153
|
-
|
154
|
-
unless ability_proc
|
155
|
-
raise ScrivitoError.new("No proc given for ability '#{ability_name}'")
|
156
|
+
def assert_no_conflict(type, verb, subject)
|
157
|
+
if @explicit_rules.has_key?([type, verb, subject])
|
158
|
+
raise ScrivitoError.new("Conflicting rules for verb '#{verb}' and subject '#{subject}'")
|
156
159
|
end
|
157
160
|
end
|
158
161
|
end
|
data/lib/scrivito/workspace.rb
CHANGED
@@ -9,6 +9,8 @@ class Workspace
|
|
9
9
|
|
10
10
|
include ModelIdentity
|
11
11
|
|
12
|
+
PublishPreventedDueToContentChange = Class.new(ScrivitoError)
|
13
|
+
|
12
14
|
# Set the currently used workspace
|
13
15
|
# @api public
|
14
16
|
# @param [Scrivito::Workspace] workspace
|
@@ -108,7 +110,17 @@ class Workspace
|
|
108
110
|
# @api public
|
109
111
|
def reload
|
110
112
|
@workspace_data = CmsBackend.instance.find_workspace_data_by_id(self.id)
|
111
|
-
|
113
|
+
|
114
|
+
# Clear all cached instance variables.
|
115
|
+
@base_revision = nil
|
116
|
+
@memberships = nil
|
117
|
+
@revision = nil
|
118
|
+
end
|
119
|
+
|
120
|
+
def api_request(verb, path, payload = nil)
|
121
|
+
response = CmsRestApi.public_send(verb, "#{backend_url}#{path}", payload)
|
122
|
+
reload if [:post, :put, :delete].include?(verb)
|
123
|
+
response
|
112
124
|
end
|
113
125
|
|
114
126
|
# Updates this workspace's attributes
|
@@ -117,8 +129,7 @@ class Workspace
|
|
117
129
|
# @return [Scrivito::Workspace]
|
118
130
|
def update(attributes)
|
119
131
|
CmsRestApi.put(backend_url, workspace: attributes)
|
120
|
-
|
121
|
-
self.reload
|
132
|
+
reload
|
122
133
|
end
|
123
134
|
|
124
135
|
# Destroy this workspace
|
@@ -131,17 +142,24 @@ class Workspace
|
|
131
142
|
# Publish the changes of this workspace
|
132
143
|
# @api public
|
133
144
|
def publish
|
134
|
-
|
145
|
+
internal_publish
|
146
|
+
end
|
135
147
|
|
136
|
-
|
148
|
+
def conditional_publish
|
149
|
+
internal_publish(if_content_state_id_equals: content_state.content_state_id)
|
150
|
+
rescue Scrivito::ClientError => e
|
151
|
+
if e.message.starts_with?('The specified condition for content_state_id')
|
152
|
+
raise PublishPreventedDueToContentChange.new(e.message)
|
153
|
+
else
|
154
|
+
raise e
|
155
|
+
end
|
137
156
|
end
|
138
157
|
|
139
158
|
# Rebases the current workspace on the published content
|
140
159
|
# @api public
|
141
160
|
def rebase
|
142
161
|
CmsRestApi.put("#{backend_url}/rebase", {})
|
143
|
-
|
144
|
-
self.reload
|
162
|
+
reload
|
145
163
|
end
|
146
164
|
|
147
165
|
# Returns the id of the workspace
|
@@ -162,7 +180,7 @@ class Workspace
|
|
162
180
|
@workspace_data.title
|
163
181
|
end
|
164
182
|
|
165
|
-
# @api
|
183
|
+
# @api public
|
166
184
|
# Returns the members of this workspace and their roles
|
167
185
|
#
|
168
186
|
# @return [MembershipsCollection]
|
@@ -216,12 +234,38 @@ class Workspace
|
|
216
234
|
@objs ||= ObjsCollection.new(self)
|
217
235
|
end
|
218
236
|
|
237
|
+
# Returns all obj classes of this working copy.
|
238
|
+
#
|
239
|
+
# @api public
|
240
|
+
#
|
241
|
+
# @example Find the obj class named "Homepage" in the "rtc" {Workspace}.
|
242
|
+
# Workspace.find('rtc').obj_classes['Homepage']
|
243
|
+
#
|
244
|
+
# @return {ObjClassCollection}
|
245
|
+
def obj_classes
|
246
|
+
@obj_classes ||= ObjClassCollection.new(self)
|
247
|
+
end
|
248
|
+
|
219
249
|
def inspect
|
220
250
|
"<#{self.class} id=\"#{id}\" title=\"#{title}\">"
|
221
251
|
end
|
222
252
|
|
253
|
+
def as_json(options = {})
|
254
|
+
{
|
255
|
+
id: id,
|
256
|
+
title: title,
|
257
|
+
memberships: memberships,
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
223
261
|
private
|
224
262
|
|
263
|
+
def internal_publish(data={})
|
264
|
+
CmsRestApi.put("#{backend_url}/publish", data)
|
265
|
+
|
266
|
+
reset_workspace_if_current
|
267
|
+
end
|
268
|
+
|
225
269
|
def backend_url
|
226
270
|
"/workspaces/#{id}"
|
227
271
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Scrivito
|
2
|
+
class Workspace
|
3
|
+
class PublishChecker < Struct.new(:workspace, :user)
|
4
|
+
MAX_EXECUTION_TIME = (0.5).second
|
5
|
+
|
6
|
+
def passing_certificates?(certificates)
|
7
|
+
begin
|
8
|
+
responses = decrypt_responses(certificates).map do |response|
|
9
|
+
response.with_indifferent_access
|
10
|
+
end
|
11
|
+
|
12
|
+
return false unless responses.all? do |response|
|
13
|
+
raise_invalid_certificates_error if response[:content_state_id].nil?
|
14
|
+
|
15
|
+
response[:content_state_id] == workspace.content_state.content_state_id
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_passing_result(responses)
|
19
|
+
true
|
20
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
21
|
+
raise_invalid_certificates_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(offset)
|
26
|
+
batch_size = Configuration.check_batch_size
|
27
|
+
objs, changed_obj_count = fetch_objs_and_count(offset, batch_size)
|
28
|
+
passed, objs = compute_publishable(objs)
|
29
|
+
|
30
|
+
if passed
|
31
|
+
passing_result(objs, changed_obj_count, offset)
|
32
|
+
else
|
33
|
+
failing_result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def decrypt_responses(certificates)
|
40
|
+
certificates.map(&message_verifier.method(:verify))
|
41
|
+
end
|
42
|
+
|
43
|
+
def fetch_objs_and_count(offset, batch_size)
|
44
|
+
enumerator = workspace.objs.changes(offset, batch_size)
|
45
|
+
[enumerator.take(batch_size), enumerator.size]
|
46
|
+
end
|
47
|
+
|
48
|
+
def passing_result(objs, changed_obj_count, offset)
|
49
|
+
until_element = offset + objs.size - 1
|
50
|
+
until_element = 'END' if until_element >= (changed_obj_count - 1)
|
51
|
+
|
52
|
+
pass_sub_hash = {
|
53
|
+
workspace_id: workspace.id,
|
54
|
+
content_state_id: workspace.content_state.content_state_id,
|
55
|
+
from: offset,
|
56
|
+
until: until_element,
|
57
|
+
}
|
58
|
+
|
59
|
+
{ result: 'pass', pass: pass_sub_hash, certificate: sign(pass_sub_hash) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def compute_publishable(objs)
|
63
|
+
start_time = Time.now
|
64
|
+
result = []
|
65
|
+
|
66
|
+
objs.each do |obj|
|
67
|
+
if publishable?(obj)
|
68
|
+
result << obj
|
69
|
+
else
|
70
|
+
return false, []
|
71
|
+
end
|
72
|
+
|
73
|
+
break if (Time.now - start_time) > MAX_EXECUTION_TIME
|
74
|
+
end
|
75
|
+
|
76
|
+
return true, result
|
77
|
+
end
|
78
|
+
|
79
|
+
def failing_result
|
80
|
+
{result: 'fail' }
|
81
|
+
end
|
82
|
+
|
83
|
+
def publishable?(obj)
|
84
|
+
obj.publishable? && user.can_publish?(obj)
|
85
|
+
end
|
86
|
+
|
87
|
+
def sign(object)
|
88
|
+
message_verifier.generate(object)
|
89
|
+
end
|
90
|
+
|
91
|
+
def message_verifier
|
92
|
+
@message_verifier ||= ActiveSupport::MessageVerifier.new(
|
93
|
+
Rails.application.secrets.secret_key_base, serializer: JSON
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
def assert_passing_result(responses)
|
98
|
+
sorted_responses = responses.sort_by do |response|
|
99
|
+
response[:from].to_i
|
100
|
+
end
|
101
|
+
|
102
|
+
last_until = sorted_responses.inject(-1) do |last_until, response|
|
103
|
+
if last_until == 'END'
|
104
|
+
raise_invalid_certificates_error
|
105
|
+
elsif (last_until + 1) == response[:from].to_i
|
106
|
+
if response[:until] == 'END'
|
107
|
+
'END'
|
108
|
+
else
|
109
|
+
response[:until].to_i
|
110
|
+
end
|
111
|
+
else
|
112
|
+
raise_invalid_certificates_error
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if last_until != 'END'
|
117
|
+
raise_invalid_certificates_error
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def raise_invalid_certificates_error
|
122
|
+
raise ScrivitoError, 'Invalid certificates'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scrivito_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Infopark AG
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -149,6 +149,7 @@ files:
|
|
149
149
|
- app/controllers/scrivito/default_cms_controller.rb
|
150
150
|
- app/controllers/scrivito/objs_controller.rb
|
151
151
|
- app/controllers/scrivito/tasks_controller.rb
|
152
|
+
- app/controllers/scrivito/users_controller.rb
|
152
153
|
- app/controllers/scrivito/webservice_controller.rb
|
153
154
|
- app/controllers/scrivito/workspaces_controller.rb
|
154
155
|
- app/helpers/cms_helper.rb
|
@@ -254,6 +255,8 @@ files:
|
|
254
255
|
- lib/scrivito/named_link.rb
|
255
256
|
- lib/scrivito/network_error.rb
|
256
257
|
- lib/scrivito/obj_class.rb
|
258
|
+
- lib/scrivito/obj_class_collection.rb
|
259
|
+
- lib/scrivito/obj_class_data.rb
|
257
260
|
- lib/scrivito/obj_data.rb
|
258
261
|
- lib/scrivito/obj_data_from_hash.rb
|
259
262
|
- lib/scrivito/obj_data_from_service.rb
|
@@ -273,6 +276,7 @@ files:
|
|
273
276
|
- lib/scrivito/widget_field_params.rb
|
274
277
|
- lib/scrivito/widget_garbage_collection.rb
|
275
278
|
- lib/scrivito/workspace.rb
|
279
|
+
- lib/scrivito/workspace/publish_checker.rb
|
276
280
|
- lib/scrivito/workspace_data_from_service.rb
|
277
281
|
- lib/scrivito/workspace_selection_middleware.rb
|
278
282
|
- lib/scrivito_sdk.rb
|