module Scrivito # @api beta class UserDefinition < Struct.new(:user_id) # Allows user to publish a workspace. # @api beta PUBLISH_WORKSPACE_ABILITY = 'publish_workspace' # Allows user to do everything. # @api beta ADMINISTRATE_CMS_ABILITY = 'administrate_cms' # @api beta ABILITY_NAMES = [ ADMINISTRATE_CMS_ABILITY, PUBLISH_WORKSPACE_ABILITY, ] # Defines a user ability. # @api beta # @param [String, Symbol] ability_name name of the ability # @param [Proc] ability_proc proc to check if the ability can be granted # @raise [Scrivito::ScrivitoError] if the given ability name is unknown # @raise [Scrivito::ScrivitoError] if no ability proc is given # @yieldreturn If the block returns a "truthy" value, then the ability will be granted # @yieldreturn If the block returns a "falsy" value, then the ability will be prohibited # @see ABILITY_NAMES # @see Scrivito::User.define # @example # allowed_user = nil # # alice = Scrivito::User.define('alice') do |user| # user.can(:publish_workspace) { allowed_user == 'alice' } # end # # bob = Scrivito::User.define('bob') do |user| # user.can(:publish_workspace) { allowed_user == 'bob' } # end # # # The users `alice` and `bob` will both be not allowed to publish workspace. # # allowed_user = 'alice' # # The user `alice` will now be allowed to publish workspace, # # but the user `bob` will still be not allowed. # # allowed_user = 'bob' # # The user `bob` will now be allowed to publish workspace, # # but the user `alice` will be not allowed again. def can(ability_name, &ability_proc) assert_valid_ability(ability_name, ability_proc) abilities[ability_name] = ability_proc end # Defines the user description to be displayed, when the user is shown in the in-place GUI. # @api beta # @param [Proc] description_proc proc to calculate the description. Defaults to the the user id. # @note The description is calculated "lazy". # @note The calculated description will be cached. # @see Scrivito::User.define # @example # alice = Scrivito::User.define('alice') {} # # User `alice` will be displayed as "alice" in the in-place GUI. # # bob = Scrivito::User.define('bob') do |user| # user.description { 'Bob Doe' } # end # # User `bob` will be displayed as "Bob Doe" in the in-place GUI. def description(&description_proc) @description_proc = description_proc end # Defines the proc for fetching users for the user autocompletion of the in-place GUI. # The user autocompletion is for example used in the details dialog of a workspace. # @api beta # @param [Proc] suggest_users_proc proc for fetching users to be suggested in the in-place GUI # @yieldparam [String] input an arbitrary string from the input field of a user autocompletion, # e.g. the first letters of a user name # @yieldreturn [Array] users that were found for the given input string # @note Only the first 20 of the returnes users will be displayed in the in-place GUI. # @note +suggest_users_proc+ may also be invoked with an empty string. # @example # class MyUserModel # def to_scrivito_user # Scrivito::User.define(id) do |user| # user.suggest_users do |input| # MyUserModel.find_by_prefix(input).map(&:to_scrivito_user) # end # end # end # end def suggest_users(&suggest_users_proc) @suggest_users_proc = suggest_users_proc end # Lets you restrict the ability of a user to publish a certain object. Each # registered callback can access a certain attribute of an object. Multiple # callbacks are possible # # @api beta # @param [Hash] options # @option options [Symbol] :uses the attribute you need in the callback # @yield [attribute] the value of the specified attribute # @yieldreturn [String, false] either return a message for the user or false if # no restriction is needed # # @note the callback is only called with {BasicObj Objs} that have the attribute # specified by the :uses option and if it is not a {BasicWidget Widget}-attribute # # @example # class MyUserModel # def to_scrivito_user # Scrivito::User.define(id) do |user| # user.restrict_obj_publish(uses: :_path) do |path| # if path.start_with?("/en") # false # else # "You are only allowed to edit the English site" # end # end # # user.restrict_obj_publish(uses: :_obj_class) do |obj_class| # if obj_class == "BlogPost" # false # else # "You are only allowed to edit Blog Posts" # end # end # end # end # end def restrict_obj_publish(options, &block) restriction_set.add(options, &block) end def user User.new(id: user_id, abilities: abilities, description_proc: @description_proc, suggest_users_proc: @suggest_users_proc, restriction_set: restriction_set) end private def restriction_set @restriction_set ||= RestrictionSet.new end def abilities @abilities ||= Hash.new(-> { false }).with_indifferent_access end def assert_valid_ability(ability_name, ability_proc) unless ABILITY_NAMES.include?(ability_name.to_s) raise ScrivitoError.new("'#{ability_name}' is not a valid ability name") end unless ability_proc raise ScrivitoError.new("No proc given for ability '#{ability_name}'") end end end end