scrivito_sdk 0.16.0 → 0.17.0
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/default_cms_controller.rb +3 -3
- data/app/controllers/scrivito/objs_controller.rb +18 -7
- data/app/controllers/scrivito/webservice_controller.rb +13 -1
- data/app/controllers/scrivito/workspaces_controller.rb +5 -1
- data/app/helpers/scrivito/cms_asset_helper.rb +8 -1
- data/app/helpers/scrivito/default_cms_routing_helper.rb +2 -4
- data/app/helpers/scrivito/display_helper.rb +0 -7
- data/app/helpers/scrivito/editing_helper.rb +10 -8
- data/app/helpers/scrivito/layout_helper.rb +4 -11
- data/config/ca-bundle.crt +1773 -1416
- data/config/cms_routes.rb +2 -2
- data/config/routes.rb +1 -0
- data/lib/assets/javascripts/scrivito_editing.js +969 -533
- data/lib/assets/stylesheets/scrivito_editing.css +99 -9
- data/lib/generators/cms/migration/templates/migration.erb +34 -6
- data/lib/generators/cms/widget/templates/migration.erb +3 -6
- data/lib/scrivito/attribute.rb +158 -0
- data/lib/scrivito/attribute_collection.rb +72 -0
- data/lib/scrivito/attribute_content.rb +39 -3
- data/lib/scrivito/basic_obj.rb +48 -27
- data/lib/scrivito/basic_widget.rb +15 -5
- data/lib/scrivito/client_config.rb +46 -19
- data/lib/scrivito/cms_field_tag.rb +1 -1
- data/lib/scrivito/cms_rest_api/attribute_serializer.rb +6 -1
- data/lib/scrivito/cms_rest_api/blob_uploader.rb +1 -1
- data/lib/scrivito/configuration.rb +32 -2
- data/lib/scrivito/connection_manager.rb +1 -6
- data/lib/scrivito/content_conversion.rb +11 -7
- data/lib/scrivito/editing_context.rb +12 -0
- data/lib/scrivito/gem_info.rb +13 -0
- data/lib/scrivito/membership.rb +26 -0
- data/lib/scrivito/memberships_collection.rb +78 -0
- data/lib/scrivito/migrations/migration.rb +1 -1
- data/lib/scrivito/migrations/migration_dsl.rb +37 -0
- data/lib/scrivito/obj_class.rb +282 -0
- data/lib/scrivito/obj_data.rb +20 -1
- data/lib/scrivito/obj_params_parser.rb +2 -0
- data/lib/scrivito/obj_search_builder.rb +1 -1
- data/lib/scrivito/obj_search_enumerator.rb +11 -6
- data/lib/scrivito/objs_collection.rb +130 -0
- data/lib/scrivito/restriction_set.rb +54 -0
- data/lib/scrivito/user.rb +114 -0
- data/lib/scrivito/user_definition.rb +159 -0
- data/lib/scrivito/widget_garbage_collection.rb +4 -4
- data/lib/scrivito/workspace.rb +13 -78
- data/lib/scrivito/workspace_data_from_service.rb +2 -0
- metadata +15 -5
data/lib/scrivito/obj_data.rb
CHANGED
@@ -23,6 +23,20 @@ module Scrivito
|
|
23
23
|
|
24
24
|
SPECIAL_KEYS = Set.new(%w[ body title blob ])
|
25
25
|
|
26
|
+
ATTRIBUTE_DEFAULT_VALUES = {
|
27
|
+
"string" => "",
|
28
|
+
"text" => "",
|
29
|
+
"html" => "",
|
30
|
+
"multienum" => [],
|
31
|
+
"linklist" => [],
|
32
|
+
"referencelist" => [],
|
33
|
+
"widget" => [],
|
34
|
+
"enum" => nil,
|
35
|
+
"binary" => nil,
|
36
|
+
"date" => nil,
|
37
|
+
"reference" => nil,
|
38
|
+
"link" => nil,
|
39
|
+
}.freeze
|
26
40
|
|
27
41
|
def value_of(attribute_name)
|
28
42
|
value_and_type_of(attribute_name).first
|
@@ -105,7 +119,12 @@ module Scrivito
|
|
105
119
|
[ObjData::MissingAttribute.new, nil]
|
106
120
|
end
|
107
121
|
else
|
108
|
-
value_and_type
|
122
|
+
value, type = value_and_type
|
123
|
+
if value.nil? && has_custom_attribute?(attribute_name)
|
124
|
+
value = ATTRIBUTE_DEFAULT_VALUES[type]
|
125
|
+
end
|
126
|
+
|
127
|
+
[value, type]
|
109
128
|
end
|
110
129
|
end
|
111
130
|
|
@@ -50,6 +50,8 @@ module Scrivito
|
|
50
50
|
ContentConversion.convert_html_links(value, @host, @port)
|
51
51
|
when 'linklist'
|
52
52
|
ContentConversion.convert_linklist_urls(value, @host, @port)
|
53
|
+
when 'link'
|
54
|
+
ContentConversion.convert_link(value, @host, @port)
|
53
55
|
when 'widget'
|
54
56
|
widget_field_params.convert(value)
|
55
57
|
else
|
@@ -110,8 +110,11 @@ module Scrivito
|
|
110
110
|
|
111
111
|
include Enumerable
|
112
112
|
|
113
|
+
attr_reader :workspace
|
114
|
+
|
113
115
|
attr_reader :query
|
114
|
-
def initialize
|
116
|
+
def initialize(workspace)
|
117
|
+
@workspace = workspace
|
115
118
|
@options = {}
|
116
119
|
end
|
117
120
|
|
@@ -284,11 +287,13 @@ module Scrivito
|
|
284
287
|
end
|
285
288
|
|
286
289
|
def format(name)
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
+
@formatter = Configuration.obj_formats[name]
|
291
|
+
|
292
|
+
unless @formatter
|
290
293
|
raise UnregisteredObjFormat, "The format with name '#{name}' is not registered."
|
291
294
|
end
|
295
|
+
|
296
|
+
self
|
292
297
|
end
|
293
298
|
|
294
299
|
# @api public
|
@@ -340,7 +345,7 @@ module Scrivito
|
|
340
345
|
request_result = CmsRestApi.get(resource_path, search_dsl(offset))
|
341
346
|
|
342
347
|
obj_ids = request_result['results'].map { |result| result['id'] || result['_id'] }
|
343
|
-
objs =
|
348
|
+
objs = workspace.objs.find_including_deleted(obj_ids)
|
344
349
|
|
345
350
|
@size = request_result['total'].to_i
|
346
351
|
|
@@ -348,7 +353,7 @@ module Scrivito
|
|
348
353
|
end
|
349
354
|
|
350
355
|
def resource_path
|
351
|
-
"workspaces/#{
|
356
|
+
"workspaces/#{workspace.id}/objs/search"
|
352
357
|
end
|
353
358
|
|
354
359
|
def search_dsl(offset)
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Scrivito
|
2
|
+
# This class allows you to retrieve Objects from a specific working copy.
|
3
|
+
# You can get an instance by accessing {Workspace#objs}.
|
4
|
+
# @api public
|
5
|
+
class ObjsCollection
|
6
|
+
attr_reader :workspace
|
7
|
+
|
8
|
+
def initialize(workspace)
|
9
|
+
@workspace = workspace
|
10
|
+
end
|
11
|
+
|
12
|
+
# Find a {BasicObj Obj} by its id.
|
13
|
+
# If the parameter is an Array containing ids, return a list of corresponding Objs.
|
14
|
+
# @param [String, Integer, Array<String, Integer>]id_or_list
|
15
|
+
# @return [Obj, Array<Obj>]
|
16
|
+
# @api public
|
17
|
+
def find(id_or_list)
|
18
|
+
find_filtering_deleted(id_or_list, false)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Find a {BasicObj Obj} by its id.
|
22
|
+
# If the parameter is an Array containing ids, return a list of corresponding Objs.
|
23
|
+
# The results include deleted objects as well.
|
24
|
+
# @param [String, Integer, Array<String, Integer>]id_or_list
|
25
|
+
# @return [Obj, Array<Obj>]
|
26
|
+
# @api public
|
27
|
+
def find_including_deleted(id_or_list)
|
28
|
+
find_filtering_deleted(id_or_list, true)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Find the {BasicObj Obj} with the given path.
|
32
|
+
# Returns +nil+ if no matching Obj exists.
|
33
|
+
# @param [String] path Path of the {BasicObj Obj}.
|
34
|
+
# @return [Obj]
|
35
|
+
# @api public
|
36
|
+
def find_by_path(path)
|
37
|
+
find_by(:path, [path]).first.first
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the {BasicObj Obj} with the given permalink, or +nil+ if no matching Obj exists.
|
41
|
+
# @param [String] permalink The permalink of the {BasicObj Obj}.
|
42
|
+
# @return [Obj]
|
43
|
+
# @api public
|
44
|
+
def find_by_permalink(permalink)
|
45
|
+
find_by(:permalink, [permalink]).first.first
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a {ObjSearchEnumerator} with the given initial subquery consisting of the four arguments.
|
49
|
+
#
|
50
|
+
# Note that +field+ and +value+ can also be arrays for searching several fields or searching for several values.
|
51
|
+
#
|
52
|
+
# {ObjSearchEnumerator}s can be chained using one of the chainable methods (e.g. {ObjSearchEnumerator#and} and {ObjSearchEnumerator#and_not}).
|
53
|
+
#
|
54
|
+
# @param [Symbol, String, Array<Symbol, String>] field See {ObjSearchEnumerator#and} for details
|
55
|
+
# @param [Symbol, String] operator See {ObjSearchEnumerator#and} for details
|
56
|
+
# @param [String, Array<String>] value See {ObjSearchEnumerator#and} for details
|
57
|
+
# @param [Hash] boost See {ObjSearchEnumerator#and} for details
|
58
|
+
# @return [ObjSearchEnumerator]
|
59
|
+
# @api public
|
60
|
+
def where(field, operator, value, boost = nil)
|
61
|
+
ObjSearchEnumerator.new(workspace)
|
62
|
+
.and(field, operator, value, boost)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns a {ObjSearchEnumerator} of all {BasicObj Obj}s.
|
66
|
+
# @return [ObjSearchEnumerator]
|
67
|
+
# @api public
|
68
|
+
def all
|
69
|
+
ObjSearchEnumerator.new(workspace).batch_size(1000)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns a {ObjSearchEnumerator} of all Objs with the given +obj_class+.
|
73
|
+
# @param [String] obj_class Name of the ObjClass.
|
74
|
+
# @return [ObjSearchEnumerator]
|
75
|
+
# @api public
|
76
|
+
def find_all_by_obj_class(obj_class)
|
77
|
+
all.and(:_obj_class, :equals, obj_class)
|
78
|
+
end
|
79
|
+
|
80
|
+
def find_by_parent_path(path)
|
81
|
+
find_by(:ppath, [path]).first
|
82
|
+
end
|
83
|
+
|
84
|
+
def find_by_id(id)
|
85
|
+
find_by(:id, [id]).first.first
|
86
|
+
end
|
87
|
+
|
88
|
+
def find_by_paths(paths)
|
89
|
+
find_by(:path, paths).map(&:first)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def find_filtering_deleted(id_or_list, include_deleted)
|
95
|
+
case id_or_list
|
96
|
+
when Array
|
97
|
+
find_by(:id, id_or_list, include_deleted).map(&:first).compact
|
98
|
+
else
|
99
|
+
obj = find_by(:id, [id_or_list.to_s], include_deleted).first.first
|
100
|
+
obj or raise ResourceNotFound, "Could not find Obj with id #{id_or_list}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# accepts the name of an "obj_by" - view, a list of keys
|
105
|
+
# and an "include_deleted" flag
|
106
|
+
# returns a list of lists of Objs: a list of Objs for each given keys.
|
107
|
+
def find_by(view, keys, include_deleted = false)
|
108
|
+
if include_deleted
|
109
|
+
finder_method_name = :find_obj_data_including_deleted_by
|
110
|
+
else
|
111
|
+
finder_method_name = :find_obj_data_by
|
112
|
+
end
|
113
|
+
|
114
|
+
result = CmsBackend.instance.public_send(
|
115
|
+
finder_method_name,
|
116
|
+
workspace.revision,
|
117
|
+
view,
|
118
|
+
keys)
|
119
|
+
|
120
|
+
result.map do |list|
|
121
|
+
list.map do |obj_data|
|
122
|
+
obj = BasicObj.instantiate(obj_data)
|
123
|
+
obj.revision = workspace.revision
|
124
|
+
|
125
|
+
obj
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Scrivito
|
2
|
+
class RestrictionSet
|
3
|
+
Restriction = Struct.new(:attribute, :callable) do
|
4
|
+
def call(obj)
|
5
|
+
if skip?(obj)
|
6
|
+
false
|
7
|
+
else
|
8
|
+
value = obj[attribute]
|
9
|
+
|
10
|
+
callable.call(value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def skip?(obj)
|
17
|
+
!obj.has_attribute?(attribute) || obj.type_of_attribute(attribute) == 'widget'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(options, &block)
|
22
|
+
options = options.with_indifferent_access
|
23
|
+
attribute = options.fetch(:uses) do
|
24
|
+
raise ScrivitoError, 'No "uses" option given when adding a publish restriction'
|
25
|
+
end
|
26
|
+
|
27
|
+
unless block_given?
|
28
|
+
raise ScrivitoError, 'No block provided when adding a publish restriction'
|
29
|
+
end
|
30
|
+
|
31
|
+
restrictions << Restriction.new(attribute, block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def restriction_messages_for(obj)
|
35
|
+
restriction_messages = restrictions.inject([]) do |messages, restriction|
|
36
|
+
message = restriction.call(obj)
|
37
|
+
|
38
|
+
if message
|
39
|
+
messages << message.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
messages
|
43
|
+
end
|
44
|
+
|
45
|
+
restriction_messages.uniq
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def restrictions
|
51
|
+
@restrictions ||= []
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Scrivito
|
2
|
+
# @api beta
|
3
|
+
class User < Struct.new(:id, :abilities, :description_proc, :suggest_users_proc, :restriction_set)
|
4
|
+
class << self
|
5
|
+
# Defines a new user.
|
6
|
+
# @api beta
|
7
|
+
# @param [String] id the unique, unalterable id of the user.
|
8
|
+
# The user id is used to associate the user with the corresponding CMS resources.
|
9
|
+
# It will be persisted in the CMS.
|
10
|
+
# @raise [Scrivito::ScrivitoError] if id is blank
|
11
|
+
# @raise [Scrivito::ScrivitoError] if id is more than 64 characters long
|
12
|
+
# @yieldparam [Scrivito::UserDefinition] user object to define abilities on
|
13
|
+
# @see Scrivito::UserDefinition#can
|
14
|
+
# @see Scrivito::UserDefinition#description
|
15
|
+
# @example
|
16
|
+
# Scrivito::User.define('alice') do |user|
|
17
|
+
# user.can(:publish_workspace) { true }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Scrivito::User.define('bob') do |user|
|
21
|
+
# user.description { 'Bob Doe' }
|
22
|
+
# user.can(:publish_workspace) { true }
|
23
|
+
# end
|
24
|
+
def define(id, &block)
|
25
|
+
assert_valid_id(id)
|
26
|
+
user_definition = UserDefinition.new(id)
|
27
|
+
yield user_definition
|
28
|
+
user_definition.user
|
29
|
+
end
|
30
|
+
|
31
|
+
def anonymous_admin
|
32
|
+
User.new(
|
33
|
+
id: nil,
|
34
|
+
abilities: Hash.new(-> {true}).with_indifferent_access,
|
35
|
+
description_proc: nil,
|
36
|
+
suggest_users_proc: nil
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def find(id)
|
41
|
+
if Configuration.find_user_proc
|
42
|
+
user = Scrivito::Configuration.find_user_proc.call(id)
|
43
|
+
assert_valid_user(user)
|
44
|
+
user
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def assert_valid_id(id)
|
51
|
+
raise ScrivitoError.new('User id can not be blank') if id.blank?
|
52
|
+
raise ScrivitoError.new('User id is too long (max length 64)') if id.length > 64
|
53
|
+
end
|
54
|
+
|
55
|
+
def assert_valid_user(user)
|
56
|
+
unless user.is_a?(User) || user.nil?
|
57
|
+
raise ScrivitoError.new("Expected an instance of #{self} or nil, but got #{user.inspect}")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(options)
|
63
|
+
super(*options.values_at(:id, :abilities, :description_proc,
|
64
|
+
:suggest_users_proc, :restriction_set))
|
65
|
+
end
|
66
|
+
|
67
|
+
def able_to?(ability_name)
|
68
|
+
!!abilities[ability_name].call
|
69
|
+
end
|
70
|
+
|
71
|
+
# Verfies if the User is able to publish changes to a certain {BasicObj Obj}
|
72
|
+
#
|
73
|
+
# @api beta
|
74
|
+
# @param [BasicObj] obj the obj that should be published
|
75
|
+
# @return [Boolean] true if the user is allowed to publish otherwise false
|
76
|
+
def can_publish?(obj)
|
77
|
+
restriction_messages_for(obj).empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Checks if the User is able to publish changes and returns the message
|
81
|
+
# specified in a {UserDefinition#restrict_obj_publish} callback if they are not
|
82
|
+
# If the user can publish the obj an empty array is returned
|
83
|
+
#
|
84
|
+
# @api beta
|
85
|
+
# @param [BasicObj] obj the obj that should be published
|
86
|
+
# @return [Array<String>] Hints why the user can't publish
|
87
|
+
def restriction_messages_for(obj)
|
88
|
+
return [] if able_to?(UserDefinition::ADMINISTRATE_CMS_ABILITY)
|
89
|
+
|
90
|
+
if obj.modification == Modification::EDITED
|
91
|
+
base_revision_obj = obj.in_revision(obj.revision.workspace.base_revision)
|
92
|
+
|
93
|
+
restriction_set.restriction_messages_for(obj) |
|
94
|
+
restriction_set.restriction_messages_for(base_revision_obj)
|
95
|
+
else
|
96
|
+
restriction_set.restriction_messages_for(obj)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def description
|
101
|
+
@description ||= calculate_description
|
102
|
+
end
|
103
|
+
|
104
|
+
def suggest_users(input)
|
105
|
+
suggest_users_proc ? suggest_users_proc.call(input) : []
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def calculate_description
|
111
|
+
description_proc ? description_proc.call : id
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Scrivito
|
2
|
+
# @api beta
|
3
|
+
class UserDefinition < Struct.new(:user_id)
|
4
|
+
# Allows user to publish a workspace.
|
5
|
+
# @api beta
|
6
|
+
PUBLISH_WORKSPACE_ABILITY = 'publish_workspace'
|
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
|
+
]
|
17
|
+
|
18
|
+
# Defines a user ability.
|
19
|
+
# @api beta
|
20
|
+
# @param [String, Symbol] ability_name name of the ability
|
21
|
+
# @param [Proc] ability_proc proc to check if the ability can be granted
|
22
|
+
# @raise [Scrivito::ScrivitoError] if the given ability name is unknown
|
23
|
+
# @raise [Scrivito::ScrivitoError] if no ability proc is given
|
24
|
+
# @yieldreturn If the block returns a "truthy" value, then the ability will be granted
|
25
|
+
# @yieldreturn If the block returns a "falsy" value, then the ability will be prohibited
|
26
|
+
# @see ABILITY_NAMES
|
27
|
+
# @see Scrivito::User.define
|
28
|
+
# @example
|
29
|
+
# allowed_user = nil
|
30
|
+
#
|
31
|
+
# alice = Scrivito::User.define('alice') do |user|
|
32
|
+
# user.can(:publish_workspace) { allowed_user == 'alice' }
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# bob = Scrivito::User.define('bob') do |user|
|
36
|
+
# user.can(:publish_workspace) { allowed_user == 'bob' }
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # The users `alice` and `bob` will both be not allowed to publish workspace.
|
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
|
51
|
+
end
|
52
|
+
|
53
|
+
# Defines the user description to be displayed, when the user is shown in the in-place GUI.
|
54
|
+
# @api beta
|
55
|
+
# @param [Proc] description_proc proc to calculate the description. Defaults to the the user id.
|
56
|
+
# @note The description is calculated "lazy".
|
57
|
+
# @note The calculated description will be cached.
|
58
|
+
# @see Scrivito::User.define
|
59
|
+
# @example
|
60
|
+
# alice = Scrivito::User.define('alice') {}
|
61
|
+
# # User `alice` will be displayed as "alice" in the in-place GUI.
|
62
|
+
#
|
63
|
+
# bob = Scrivito::User.define('bob') do |user|
|
64
|
+
# user.description { 'Bob Doe' }
|
65
|
+
# end
|
66
|
+
# # User `bob` will be displayed as "Bob Doe" in the in-place GUI.
|
67
|
+
def description(&description_proc)
|
68
|
+
@description_proc = description_proc
|
69
|
+
end
|
70
|
+
|
71
|
+
# Defines the proc for fetching users for the user autocompletion of the in-place GUI.
|
72
|
+
# The user autocompletion is for example used in the details dialog of a workspace.
|
73
|
+
# @api beta
|
74
|
+
# @param [Proc] suggest_users_proc proc for fetching users to be suggested in the in-place GUI
|
75
|
+
# @yieldparam [String] input an arbitrary string from the input field of a user autocompletion,
|
76
|
+
# e.g. the first letters of a user name
|
77
|
+
# @yieldreturn [Array<Scrivito::User>] users that were found for the given input string
|
78
|
+
# @note Only the first 20 of the returnes users will be displayed in the in-place GUI.
|
79
|
+
# @note +suggest_users_proc+ may also be invoked with an empty string.
|
80
|
+
# @example
|
81
|
+
# class MyUserModel
|
82
|
+
# def to_scrivito_user
|
83
|
+
# Scrivito::User.define(id) do |user|
|
84
|
+
# user.suggest_users do |input|
|
85
|
+
# MyUserModel.find_by_prefix(input).map(&:to_scrivito_user)
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
def suggest_users(&suggest_users_proc)
|
91
|
+
@suggest_users_proc = suggest_users_proc
|
92
|
+
end
|
93
|
+
|
94
|
+
# Lets you restrict the ability of a user to publish a certain object. Each
|
95
|
+
# registered callback can access a certain attribute of an object. Multiple
|
96
|
+
# callbacks are possible
|
97
|
+
#
|
98
|
+
# @api beta
|
99
|
+
# @param [Hash] options
|
100
|
+
# @option options [Symbol] :uses the attribute you need in the callback
|
101
|
+
# @yield [attribute] the value of the specified attribute
|
102
|
+
# @yieldreturn [String, false] either return a message for the user or false if
|
103
|
+
# no restriction is needed
|
104
|
+
#
|
105
|
+
# @note the callback is only called with {BasicObj Objs} that have the attribute
|
106
|
+
# specified by the :uses option and if it is not a {BasicWidget Widget}-attribute
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# class MyUserModel
|
110
|
+
# def to_scrivito_user
|
111
|
+
# Scrivito::User.define(id) do |user|
|
112
|
+
# user.restrict_obj_publish(uses: :_path) do |path|
|
113
|
+
# if path.start_with?("/en")
|
114
|
+
# false
|
115
|
+
# else
|
116
|
+
# "You are only allowed to edit the English site"
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# user.restrict_obj_publish(uses: :_obj_class) do |obj_class|
|
121
|
+
# if obj_class == "BlogPost"
|
122
|
+
# false
|
123
|
+
# else
|
124
|
+
# "You are only allowed to edit Blog Posts"
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
def restrict_obj_publish(options, &block)
|
131
|
+
restriction_set.add(options, &block)
|
132
|
+
end
|
133
|
+
|
134
|
+
def user
|
135
|
+
User.new(id: user_id, abilities: abilities, description_proc: @description_proc,
|
136
|
+
suggest_users_proc: @suggest_users_proc, restriction_set: restriction_set)
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def restriction_set
|
142
|
+
@restriction_set ||= RestrictionSet.new
|
143
|
+
end
|
144
|
+
|
145
|
+
def abilities
|
146
|
+
@abilities ||= Hash.new(-> { false }).with_indifferent_access
|
147
|
+
end
|
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
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|