require File.dirname(__FILE__) + '/exceptions' require File.dirname(__FILE__) + '/identity' module Authorization module ObjectRolesTable module UserExtensions def self.included( recipient ) recipient.extend( ClassMethods ) end module ClassMethods def acts_as_authorized_user(roles_relationship_opts = {}) has_and_belongs_to_many :roles, roles_relationship_opts include Authorization::ObjectRolesTable::UserExtensions::InstanceMethods include Authorization::Identity::UserExtensions::InstanceMethods # Provides all kinds of dynamic sugar via method_missing end end module InstanceMethods # If roles aren't explicitly defined in user class then check roles table def has_role?( role_name, authorizable_obj = nil ) if authorizable_obj.nil? self.roles.find_by_name( role_name ) ? true : false # If we ask a general role question, return true if any role is defined. else role = get_role( role_name, authorizable_obj ) role ? self.roles.exists?( role.id ) : false end end def has_role( role_name, authorizable_obj = nil ) role = get_role( role_name, authorizable_obj ) if role.nil? if authorizable_obj.is_a? Class role = Role.create( :name => role_name, :authorizable_type => authorizable_obj.to_s ) elsif authorizable_obj role = Role.create( :name => role_name, :authorizable => authorizable_obj ) else role = Role.create( :name => role_name ) end end self.roles << role if role and not self.roles.exists?( role.id ) end def has_no_role( role_name, authorizable_obj = nil ) role = get_role( role_name, authorizable_obj ) if role self.roles.delete( role ) role.destroy if role.users.empty? end end def has_roles_for?( authorizable_obj ) if authorizable_obj.is_a? Class !self.roles.detect { |role| role.authorizable_type == authorizable_obj.to_s }.nil? elsif authorizable_obj !self.roles.detect { |role| role.authorizable_type == authorizable_obj.class.base_class.to_s && role.authorizable == authorizable_obj }.nil? else !self.roles.detect { |role| role.authorizable.nil? }.nil? end end alias :has_role_for? :has_roles_for? def roles_for( authorizable_obj ) if authorizable_obj.is_a? Class self.roles.select { |role| role.authorizable_type == authorizable_obj.to_s } elsif authorizable_obj self.roles.select { |role| role.authorizable_type == authorizable_obj.class.base_class.to_s && role.authorizable.id == authorizable_obj.id } else self.roles.select { |role| role.authorizable.nil? } end end def authorizables_for( authorizable_class ) unless authorizable_class.is_a? Class raise CannotGetAuthorizables, "Invalid argument: '#{authorizable_class}'. You must provide a class here." end authorizables = self.roles.inject([]) do |result, role| if role.authorizable_type == authorizable_class.to_s && !result.include?(role.authorizable) result << role.authorizable end result end authorizables.compact end private def get_role( role_name, authorizable_obj ) if authorizable_obj.is_a? Class Role.find( :first, :conditions => [ 'name = ? and authorizable_type = ? and authorizable_id IS NULL', role_name, authorizable_obj.to_s ] ) elsif authorizable_obj Role.find( :first, :conditions => [ 'name = ? and authorizable_type = ? and authorizable_id = ?', role_name, authorizable_obj.class.base_class.to_s, authorizable_obj.id ] ) else Role.find( :first, :conditions => [ 'name = ? and authorizable_type IS NULL and authorizable_id IS NULL', role_name ] ) end end end end module ModelExtensions def self.included( recipient ) recipient.extend( ClassMethods ) end module ClassMethods def acts_as_authorizable has_many :accepted_roles, :as => :authorizable, :class_name => 'Role', :dependent => :destroy def accepts_role?( role_name, user ) user.has_role? role_name, self end def accepts_role( role_name, user ) user.has_role role_name, self end def accepts_no_role( role_name, user ) user.has_no_role role_name, self end def accepts_roles_by?( user ) user.has_roles_for? self end alias :accepts_role_by? :accepts_roles_by? def accepted_roles_by( user ) user.roles_for self end def authorizables_by( user ) user.authorizables_for self end include Authorization::ObjectRolesTable::ModelExtensions::InstanceMethods include Authorization::Identity::ModelExtensions::InstanceMethods # Provides all kinds of dynamic sugar via method_missing end end module InstanceMethods # If roles aren't overriden in model then check roles table def accepts_role?( role_name, user ) user.has_role? role_name, self end def accepts_role( role_name, user ) user.has_role role_name, self end def accepts_no_role( role_name, user ) user.has_no_role role_name, self end def accepts_roles_by?( user ) user.has_roles_for? self end alias :accepts_role_by? :accepts_roles_by? def accepted_roles_by( user ) user.roles_for self end end end end end