class Padrino::Permissions

Class to store and check permissions used in Padrino::Access.

Public Class Methods

new() click to toggle source

Initializes new permissions storage.

@example

permissions = Permissions.new
# File lib/padrino-auth/permissions.rb, line 12
def initialize
  clear!
end

Public Instance Methods

add(*args) click to toggle source

Adds a permission record to storage.

@param [Symbol || Object] subject

permit subject

@param [Hash] options

permit attributes

@param [Symbol] options || options

what action to allow with objects

@param [Symbol] options || options

with what objects allow specified action

@example

permissions.add :robots, :allow => :protect, :object => :humans
permissions.add @bender, :allow => :kill, :object => :humans
# File lib/padrino-auth/permissions.rb, line 43
def add(*args)
  @actions = {}
  options = args.extract_options!
  action, object = action_and_object(options)
  object_type = detect_type(object)
  args.each{ |subject| merge(subject, action, object_type) }
end
check(subject, options) { |: true)| ... } click to toggle source

Checks if permission record exists. Returns a boolean or yield a block.

@param [Object] subject

performer of an action

@param [Hash] options

attributes to check

@param [Symbol] options

check if the subject has a role

@param [Symbol] options || options

check if the subject is allowed to perform the action

@param [Symbol] options || options

check if the subject is allowed to interact with the subject

@param [Proc]

optional block to yield if the action is allowed

@example

# check if @bender have role :robots
permissions.check @bender, :have => :robots # => true
# check if @bender is allowed to kill :humans
permissions.check @bender, :allow => :kill, :object => :humans # => true
# check if @bender is allowed to kill :humans and yield a block
permissions.check @bender, :allow => :kill, :object => :humans do
  @bender.kill_all! :humans
end
# File lib/padrino-auth/permissions.rb, line 77
def check(subject, options)
  case
  when options[:have]
    check_role(subject, options[:have])
  else
    check_action(subject, *action_and_object(options))
  end && (block_given? ? yield : true)
end
clear!() click to toggle source

Clears permit records and action cache.

@example

permissions.clear!
# File lib/padrino-auth/permissions.rb, line 22
def clear!
  @permits = {}
  @actions = {}
end
find_objects(subject, target_action=nil) click to toggle source

Populates and returns the list of objects available to the subject.

@param [Object] subject

the subject to be checked for actions
# File lib/padrino-auth/permissions.rb, line 92
def find_objects(subject, target_action=nil)
  find_actions(subject).inject([]) do |all,(action,objects)|
    all |= objects if target_action.nil? || action == target_action || action == :*
    all
  end
end

Private Instance Methods

action_and_object(options) click to toggle source

Utility function to extract action and object from options. Defaults to [:*, :*]

action_and_object(:allow => :kill, :object => :humans)    # => [:kill, :humans]
action_and_object(:action => :romance, :with => :mutants) # => [:romance, :mutants]
action_and_object({})                                     # => [:*, :*]
# File lib/padrino-auth/permissions.rb, line 176
def action_and_object(options)
  [options[:allow] || options[:action] || :*, options[:with] || options[:object] || :*]
end
check_action(subject, action, object) click to toggle source

Checks if the subject is allowed to perform the action with the object.

# File lib/padrino-auth/permissions.rb, line 121
def check_action(subject, action, object)
  actions = find_actions(subject)
  objects = actions && (Array(actions[action]) | Array(actions[:*]))
  objects && (objects & [:*, detect_type(object)]).any?
end
check_role(subject, roles) click to toggle source

Checks if the subject has the role.

# File lib/padrino-auth/permissions.rb, line 112
def check_role(subject, roles)
  if subject.respond_to?(:role)
    Array(roles).include?(subject.role)
  else
    false
  end
end
detect_id(subject) click to toggle source

Returns parametrized subject.

detect_id :robots               # => :robots
detect_id sluggable_ar_resource # => 'Sluggable-resource-slug'
detect_id some_resource_with_id # => '4'
detect_id generic_object        # => "<Object:0x00001234>"
# File lib/padrino-auth/permissions.rb, line 159
def detect_id(subject)
  case
  when Symbol === subject
    subject
  when subject.respond_to?(:to_param)
    subject.to_param
  when subject.respond_to?(:id)
    subject.id.to_s
  else
    "#{subject}"
  end
end
detect_type(object) click to toggle source

Returns object type.

detect_type :humans # => :human
detect_type 'foobar' # => 'foobar'
# File lib/padrino-auth/permissions.rb, line 145
def detect_type(object)
  case object
  when Symbol
    object.to_s.singularize.to_sym
  else
    object
  end
end
find_actions(subject) click to toggle source

Finds all permits for the subject. Caches the permits in @actions.

find_actions(@bender) # => { :kill => { :humans }, :drink => { :booze }, :* => { :login } }
# File lib/padrino-auth/permissions.rb, line 129
def find_actions(subject)
  subject_id = detect_id(subject)
  return @actions[subject_id] if @actions[subject_id]
  actions = @permits[subject_id] || {}
  if subject.respond_to?(:role) && (role_actions = @permits[subject.role.to_sym])
    actions.merge!(role_actions){ |_,left,right| Array(left)|Array(right) }
  end
  if public_actions = @permits[:*]
    actions.merge!(public_actions){ |_,left,right| Array(left)|Array(right) }
  end
  @actions[subject_id] = actions
end
merge(subject, actions, object_type) click to toggle source

Merges a list of new permits into permissions storage.

# File lib/padrino-auth/permissions.rb, line 102
def merge(subject, actions, object_type)
  subject_id = detect_id(subject)
  @permits[subject_id] ||= {}
  Array(actions).each do |action|
    @permits[subject_id][action] ||= []
    @permits[subject_id][action] |= [object_type]
  end
end