lib/scrivito/user.rb in scrivito_sdk-0.17.0 vs lib/scrivito/user.rb in scrivito_sdk-0.18.0
- old
+ new
@@ -1,44 +1,70 @@
module Scrivito
- # @api beta
- class User < Struct.new(:id, :abilities, :description_proc, :suggest_users_proc, :restriction_set)
+ # @api public
+ class User
+ # Valid action verbs for the explicit rules.
+ # @api public
+ VERBS = [
+ :create,
+ :delete,
+ :invite_to,
+ :publish,
+ :read,
+ :write,
+ ].freeze
+
class << self
# Defines a new user.
- # @api beta
+ # @api public
# @param [String] id the unique, unalterable id of the user.
# The user id is used to associate the user with the corresponding CMS resources.
# It will be persisted in the CMS.
# @raise [Scrivito::ScrivitoError] if id is blank
# @raise [Scrivito::ScrivitoError] if id is more than 64 characters long
- # @yieldparam [Scrivito::UserDefinition] user object to define abilities on
- # @see Scrivito::UserDefinition#can
+ # @yieldparam [Scrivito::UserDefinition] user object to define rules on
+ # @see Scrivito::UserDefinition#can_always
+ # @see Scrivito::UserDefinition#can_never
# @see Scrivito::UserDefinition#description
+ # @see Scrivito::UserDefinition#restrict_obj_publish
+ # @see Scrivito::UserDefinition#suggest_users
# @example
# Scrivito::User.define('alice') do |user|
- # user.can(:publish_workspace) { true }
+ # user.description { 'Alice Almighty' }
+ # user.can_always(:read, :workspace)
+ # user.can_always(:write, :workspace)
+ # user.can_always(:publish, :workspace, 'You can always publish workspaces.')
# end
#
# Scrivito::User.define('bob') do |user|
# user.description { 'Bob Doe' }
- # user.can(:publish_workspace) { true }
+ # user.can_never(:create, :workspace, 'You are not allowed to create workspaces.')
+ # user.can_always(:read, :workspace)
+ # user.restrict_obj_publish(using: :_obj_class) do |obj_class|
+ # if obj_class.name == 'BlogPost'
+ # false
+ # else
+ # 'You are not allowed to publish blog posts.'
+ # end
+ # end
# end
- def define(id, &block)
+ def define(id)
assert_valid_id(id)
user_definition = UserDefinition.new(id)
- yield user_definition
+ yield user_definition if block_given?
user_definition.user
end
def anonymous_admin
- User.new(
- id: nil,
- abilities: Hash.new(-> {true}).with_indifferent_access,
- description_proc: nil,
- suggest_users_proc: nil
- )
+ explicit_rules = {}
+ VERBS.each { |verb| explicit_rules[[:can_always, verb, :workspace]] = nil }
+ new(id: nil, explicit_rules: explicit_rules)
end
+ def unknown_user(id)
+ new(id: id, explicit_rules: {})
+ end
+
def find(id)
if Configuration.find_user_proc
user = Scrivito::Configuration.find_user_proc.call(id)
assert_valid_user(user)
user
@@ -57,37 +83,60 @@
raise ScrivitoError.new("Expected an instance of #{self} or nil, but got #{user.inspect}")
end
end
end
+ attr_reader :id, :explicit_rules, :description_proc, :suggest_users_proc, :restriction_set
+
def initialize(options)
- super(*options.values_at(:id, :abilities, :description_proc,
- :suggest_users_proc, :restriction_set))
+ @id = options[:id]
+ @explicit_rules = options[:explicit_rules]
+ @description_proc = options[:description_proc]
+ @suggest_users_proc = options[:suggest_users_proc]
+ @restriction_set = options[:restriction_set]
+
+ @explicit_rules.each_key { |rule| assert_valid_verb(rule.second) }
end
- def able_to?(ability_name)
- !!abilities[ability_name].call
+ def can?(verb, workspace)
+ assert_valid_verb(verb)
+ can_always?(verb, :workspace) || owner_of?(workspace) && !can_never?(verb, :workspace)
end
+ def can_always?(verb, subject)
+ assert_valid_verb(verb)
+ @explicit_rules.has_key?([:can_always, verb, subject])
+ end
+
+ def can_never?(verb, subject)
+ assert_valid_verb(verb)
+ @explicit_rules.has_key?([:can_never, verb, subject])
+ end
+
+ def owner_of?(workspace)
+ membership = workspace.memberships[self]
+ membership ? membership.role == 'owner' : false
+ end
+
# Verfies if the User is able to publish changes to a certain {BasicObj Obj}
#
- # @api beta
+ # @api public
# @param [BasicObj] obj the obj that should be published
# @return [Boolean] true if the user is allowed to publish otherwise false
def can_publish?(obj)
restriction_messages_for(obj).empty?
end
# Checks if the User is able to publish changes and returns the message
# specified in a {UserDefinition#restrict_obj_publish} callback if they are not
# If the user can publish the obj an empty array is returned
#
- # @api beta
+ # @api public
# @param [BasicObj] obj the obj that should be published
# @return [Array<String>] Hints why the user can't publish
def restriction_messages_for(obj)
- return [] if able_to?(UserDefinition::ADMINISTRATE_CMS_ABILITY)
+ return [] if can_always?(:publish, :workspace)
if obj.modification == Modification::EDITED
base_revision_obj = obj.in_revision(obj.revision.workspace.base_revision)
restriction_set.restriction_messages_for(obj) |
@@ -100,15 +149,32 @@
def description
@description ||= calculate_description
end
def suggest_users(input)
- suggest_users_proc ? suggest_users_proc.call(input) : []
+ if suggest_users_proc
+ suggested_users = suggest_users_proc.call(input)
+ suggested_users.nil? ? [] : suggested_users
+ else
+ user = self.class.find(input)
+ user ? [user] : []
+ end
end
+ def as_json(options = nil)
+ {
+ id: id,
+ description: description,
+ }
+ end
+
private
def calculate_description
description_proc ? description_proc.call : id
+ end
+
+ def assert_valid_verb(verb)
+ raise ScrivitoError.new("Invalid verb '#{verb}'") unless VERBS.include?(verb)
end
end
end