class Shark::Permissions::List

Attributes

rules[R]

Public Class Methods

dump(list) click to toggle source

For Serializaton

@return [String] @api public

# File lib/shark/permissions/list.rb, line 261
def self.dump(list)
  list&.to_json
end
load(json) click to toggle source

For Deserializaton

@return [Shark::Permissions::List] @api public

# File lib/shark/permissions/list.rb, line 249
def self.load(json)
  if json.nil?
    new
  else
    new(JSON.parse(json))
  end
end
new(rules = {}) click to toggle source
# File lib/shark/permissions/list.rb, line 11
def initialize(rules = {})
  case rules
  when Shark::Permissions::List
    @rules = to_permission_rules(rules.as_json)
  when Hash
    @rules = to_permission_rules(rules)
  else
    raise ArgumentError, 'Rules must be a subtype of Hash'
  end
end

Public Instance Methods

<<(rule) click to toggle source

@api public

# File lib/shark/permissions/list.rb, line 29
def <<(rule)
  @rules[rule.resource] = rule
end
==(other) click to toggle source

@return [Boolean] @api public

# File lib/shark/permissions/list.rb, line 24
def ==(other)
  rules == other.rules
end
as_json(*args) click to toggle source

@return [Hash] @api public

# File lib/shark/permissions/list.rb, line 241
def as_json(*args)
  rules.as_json(*args)
end
authorized?(privilege, *resources) click to toggle source

@example:

list.authorized?(:admin, :paragraph, :contracts)
# => true
list.authorized?([:read, :write], :datenraum, :berlin)
# => false

@return [Boolean] @api public

# File lib/shark/permissions/list.rb, line 185
def authorized?(privilege, *resources)
  if privilege == Shark::Permissions.any_matcher
    privileges(*resources).present?
  else
    privilege_array = Array(privilege).map(&:to_s)
    privileges_for_resource = privileges(*resources)
    privilege_array.any? { |p| privileges_for_resource.fetch(p, false) }
  end
end
changes() click to toggle source
# File lib/shark/permissions/list.rb, line 39
def changes
  changed_rules = rules.select { |_key, rule| rule.changed? }.to_h
  self.class.new(changed_rules)
end
clone() click to toggle source

Returns a new Permissions::List with same rules.

@return [Permissions::List] @api public

# File lib/shark/permissions/list.rb, line 48
def clone
  cloned_rules = {}
  rules.each { |k, rule| cloned_rules[k] = rule.clone }

  self.class.new(cloned_rules)
end
compact() click to toggle source

Returns a new Permissions::List without any rules that have no privileges.

@return [Permissions::List] @api public

# File lib/shark/permissions/list.rb, line 59
def compact
  new_rules = {}

  rules.keys.sort.each do |k|
    rule = rules[k].clone
    new_rules[k] = rule unless rule.empty?
  end

  self.class.new(new_rules)
end
delete(key) click to toggle source
# File lib/shark/permissions/list.rb, line 70
def delete(key)
  case key
  when String
    rules.delete(key)
  when Permissions::Rule
    rules.delete(key.resource)
  else
    raise ArgumentError, 'Argument must be a String or Permissions::Rule'
  end
end
filter(names)
Alias for: select
map(&block) click to toggle source

@return [Array] @api public

# File lib/shark/permissions/list.rb, line 35
def map(&block)
  rules.values.map(&block)
end
merge(other_list) click to toggle source

@param other_list [Shark::Permissions::List] @return [Hash] @api public

# File lib/shark/permissions/list.rb, line 113
def merge(other_list)
  clone.merge!(other_list)
end
merge!(other_list) click to toggle source

Merges another list into this list. Allowed privileges are not removed. Changes are not tracked.

@param other_list [Shark::Permissions::List] @return [Hash] @api public

# File lib/shark/permissions/list.rb, line 123
def merge!(other_list)
  other_list.each do |resource, rule|
    if rules.key?(resource)
      privileges = rules[resource].privileges
      rule.privileges.each { |k, v| privileges[k] = privileges[k] || v }
    else
      rules[resource] = rule.clone
    end
  end

  self
end
privileges(*resources) click to toggle source

@example:

list.privileges(:paragraph, :contracts)
# => { 'admin' => true, 'edit' => true }

@return [Hash] @api public

# File lib/shark/permissions/list.rb, line 157
def privileges(*resources)
  matching_resources = matching_resources(*resources)
  privileges_set = Set.new

  matching_resources.each do |name|
    rule = rules[name]

    next unless rule

    case rule.effect
    when 'ALLOW'
      privileges_set.merge(rule.privileges_as_array)
    when 'DENY'
      privileges.subtract(rule.privileges_as_array)
    end
  end

  privileges_set.map { |k| [k, true] }.to_h
end
reject(names) click to toggle source
# File lib/shark/permissions/list.rb, line 97
def reject(names)
  filtered_rules = {}

  rejected_keys = select(names).keys
  rules.each do |name, rule|
    next if rejected_keys.include?(name)

    filtered_rules[rule.resource] = rule.clone
  end

  self.class.new(filtered_rules)
end
remove_inherited_rules() click to toggle source

Returns new list without inherited privileges and empty rules.

@return [Permissions::List] @api public

# File lib/shark/permissions/list.rb, line 222
def remove_inherited_rules
  new_list = self.class.new({})

  rules.keys.sort.each do |name|
    new_rule = Permissions::Rule.new(resource: name)
    parent = new_rule.parent

    rules[name].privileges.each do |k, v|
      new_rule.privileges[k] = v if v && !new_list.authorized?(k, parent)
    end

    new_list << new_rule unless new_rule.empty?
  end

  new_list
end
select(names) click to toggle source
# File lib/shark/permissions/list.rb, line 81
def select(names)
  filtered_rules = {}

  Array(names).each do |filter_name|
    filter_resource = Permissions::Resource.new(filter_name)
    rules.each do |name, rule|
      next unless filter_resource.super_resource_of?(name)

      filtered_rules[rule.resource] = rule.clone
    end
  end

  self.class.new(filtered_rules)
end
Also aliased as: filter
set_inherited_privileges!() click to toggle source

Correctly set privileges for subresources.

@return [Permissions::List] @api public

# File lib/shark/permissions/list.rb, line 209
def set_inherited_privileges!
  rules.each do |resource, rule|
    privileges = privileges(resource)
    privileges.each { |k, v| rule.privileges[k] = v if rule.privileges.key?(k) }
  end

  self
end
subresource_authorized?(privilege, *resources) click to toggle source

@example:

list.subresource_authorized?(:admin, :paragraph, :contracts)
# => true

@return [Boolean] @api public

# File lib/shark/permissions/list.rb, line 201
def subresource_authorized?(privilege, *resources)
  authorized?(privilege, *resources, Shark::Permissions.any_matcher)
end
update(other_list) click to toggle source

Updates this list with rules from another list. All affected rules are updated and changes are tracked.

@param other_list [Shark::Permissions::List] @return [Hash] @api public

# File lib/shark/permissions/list.rb, line 142
def update(other_list)
  other_list.each do |resource, other_rule|
    rules[resource] = Permissions::Rule.new(resource: resource) unless rules.key?(resource)
    rules[resource].update(other_rule)
  end

  self
end

Private Instance Methods

matching_resources(*resources) click to toggle source
# File lib/shark/permissions/list.rb, line 280
def matching_resources(*resources)
  resource = Resource.new(resources)
  result = resource.ancestors_and_self

  if resource.wildcard?
    result = resource.ancestors
    subresources = rules.keys.select { |name| resource.super_resource_of?(name) }
    result.concat(subresources)
  end

  result
end
to_permission_rules(rules) click to toggle source
# File lib/shark/permissions/list.rb, line 267
def to_permission_rules(rules)
  return {} if rules.blank?

  if rules.values.first.is_a?(Permissions::Rule)
    # do nothing
  else
    rules = rules.map { |k, v| [k.to_s, Permissions::Rule.new(v)] }
    rules = Hash[rules]
  end

  rules
end