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