scrivito_sdk 0.16.0 → 0.17.0
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/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
|