1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
class Six
class NoPackError < StandardError
def message
"No such pack"
end
end
class InvalidPackPassed < StandardError
def message
"Wrong Rule Pack. You must provide correct 'allowed' method"
end
end
class InitializeArgumentError < StandardError
def message
"Six.new require hash as pack argument in format {:name_of_pack => PackRules.new}"
end
end
attr_reader :rules_packs
attr_reader :current_rule_pack
# Initialize ability object
#
# == Parameters:
# packs::
# A Hash or rules to add with initializtion
#
# == Returns:
# self
#
def initialize(packs={})
raise InitializeArgumentError.new unless packs.kind_of?(Hash)
@rules_packs = {}
@current_rule_pack = nil
packs.each { |key, pack| add_pack!(key, pack) }
end
# Set current pack from stored packs by key
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
#
# == Returns:
# self or false
#
def use_pack(name)
if pack_exist?(name)
@current_rule_pack = name.to_sym
self
end
end
# Same as use but raise exception if no pack found
def use_pack!(name)
use_pack(name) ? self : raise_no_such_pack
end
# Add pack to authorization class
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
# pack::
# Any kind of object responding to allowed method
#
# == Returns:
# true or false
#
def add_pack(name, pack)
rules_packs[name.to_sym] = pack if valid_rules_object?(pack)
end
# Same as add_pack but raise exception if pack is invalid
def add_pack!(name, pack)
add_pack(name, pack) || raise_incorrect_pack_object
end
# Add pack to authorization class w/o key
#
# == Parameters:
# pack::
# Any kind of object responding to allowed method
#
# == Returns:
# true or raise exception
#
def <<(pack)
add_pack!(pack.object_id.to_s, pack)
end
# Remove pack from authorization class
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
#
# == Returns:
# true or false
#
def remove_pack(name)
if pack_exist?(name)
@current_rule_pack = nil if rules_packs[name.to_sym] == @current_rule_pack
rules_packs.delete(name.to_sym)
end
end
# Same as remove_pack but raise exception if pack wasnt found
def remove_pack!(name)
remove_pack(name) || raise_no_such_pack
end
# Check if object for rule pack is valid
#
# == Parameters:
# pack::
# Any kind of object responding to allowed method
#
# == Returns:
# true or false
#
def valid_rules_object?(object)
object.respond_to?(:allowed) &&
object.send(:allowed, nil, nil).kind_of?(Array)
rescue
false
end
# Check if authorization class has pack with such name
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
#
# == Returns:
# true or false
#
def pack_exist?(name)
rules_packs.has_key?(name.to_sym)
end
# Check if authorization class allow access for object to subject
# using selected pack or all stored.
# Basically this method
# 1. send :allowed for every stored object in packs and pass object & subject
# 2. check if any of results include allowed action
#
# == Parameters:
# action::
# Action name to check for access
# object::
# object trying to access resource
# subject::
# resource
#
# == Returns:
# true or false
#
def allowed?(object, actions, subject)
# if multiple actions passed
# check all actions to be allowed
if actions.respond_to?(:each)
actions.all? { |action| action_included?(object, action, subject) }
else
# single action check
action_included?(object, actions, subject)
end
end
# Reset current used rule pack so auth class use
# global allowed? for new request
def reset_use
@current_rule_pack = nil
end
protected
def action_included?(object, action, subject)
if current_rule_pack
rules_packs[current_rule_pack].allowed(object, subject).include?(action)
else
rules_packs.values.map { |rp| rp.allowed(object, subject) }.flatten.include?(action)
end
end
def raise_no_such_pack
raise Six::NoPackError.new
end
def raise_incorrect_pack_object
raise Six::InvalidPackPassed.new
end
# shotcuts for long methods
alias_method :use, :use_pack
alias_method :use!, :use_pack!
alias_method :add, :add_pack
alias_method :add!, :add_pack!
alias_method :remove, :remove_pack
alias_method :remove!, :remove_pack!
alias_method :reset, :reset_use
alias_method :exist?, :pack_exist?
end
|