module IdPlease class AssignmentLink attr_reader :subject, :target, :role, :via def initialize(*args) options = args.extract_options! if (assignment = options[:assignment]) @subject = assignment.subject @target = assignment.role.authorizable @role = assignment.role.name else @subject = options.delete(:subject) || raise("subject must be specified") @target = options.delete(:target) || raise("target must be specified") @role = options.delete(:role) || raise("role must be specified") end @role = @role.to_sym @via = options.delete(:via) end end class AssignmentMap attr_reader :subjects, :calculated def initialize(*args) options = args.extract_options! options = {:direction => :down, :nested => true, :members_only => false}.merge(options) @subjects = options[:subjects] # || raise("You must provide a subject") @subjects = [@subjects] unless @subjects.kind_of?(Array) @direction = options[:direction] @assign_class = options[:assignment_class] # || raise("You must provide the assignment class through :assignment_class") @nested = options[:nested] @member_role = options[:member_role] || :member @members_only = options[:members_only] @assignments = [] @calculated = false add_all_assignments(@subjects) end def add_all_assignments(subjects) @calculated = false search_proc = lambda { @direction == :down ? @assign_class.role_authorizable_eq(*subjects) : @assign_class.subject_eq(*subjects) } search_with_role = lambda { |a| @members_only ? a.role_name_eq(@member_role.to_s) : a} assignments = search_with_role.call(search_proc.call).all(:include => [:subject, {:role => :authorizable}]) @assignments += assignments if @nested subjects_to_search = if @direction == :down assignments.select { |a| a.role.name.to_sym == @member_role}.collect(&:subject).select { |s| s._auth_is_group } else assignments.select { |a| a.role.name.to_sym == @member_role}.collect { |a| a.role.authorizable }.select { |s| s.respond_to?(:_auth_is_group) && s._auth_is_group } end add_all_assignments(subjects_to_search) unless subjects_to_search.empty? end end def subjects calculate! unless @calculated @assignment_links.collect(&:subject).uniq end def subject_hash calculate! unless @calculated result = {} @assignment_links.each do |a| result[a.subject] ||= [] result[a.subject] << a.role end result.each_pair { |k,v| result[k] = v.uniq } return result end def roles calculate! unless @calculated @roles = @assignment_links.collect(&:role).uniq end def role_hash calculate! unless @calculated result = {} @assignment_links.each do |a| result[a.role] ||= [] result[a.role] << a.subject end result.each_pair { |k,v| result[k] = v.uniq } return result end def role_with_assignments calculate! unless @calculated result = Hash.new { |h,k| h[k] = Hash.new() } @assignment_links.each do |a| result[a.role][a.subject] ||= [] result[a.role][a.subject] << a.target end result.each_key { |name| result[name].each_pair { |subject,v| result[name][subject] = v.uniq }} return result end def targets calculate! unless @calculated @targets = @assignment_links.collect(&:target).uniq end def targets_with_assignments calculate! unless @calculated result = Hash.new { |h,k| h[k] = Hash.new() } @assignment_links.each do |a| result[a.role][a.target] ||= [] result[a.role][a.target] << (a.via || a.subject) end result.each_key { |name| result[name].each_pair { |target,v| result[name][target] = v.compact.uniq }} return result end def map return self end private def calculate! @assignments = @assignments.uniq @subject_hash = {} @role_link_hash = {} @assignment_links = [] @assignments.select { |a| !@members_only || a.role.name.to_sym == @member_role }.each do |a| al = AssignmentLink.new(:assignment => a) @assignment_links << al end @assignment_links.select { |al| al.role != @member_role }.each do |al| all_members_of(al.subject).each do |member| @assignment_links << AssignmentLink.new(:role => al.role, :target => al.target, :subject => member, :via => al.subject) end end end def all_members_of(*subjects) members = @assignment_links.select { |al| al.role == @member_role && subjects.include?(al.target)}.collect(&:subject) groups = members.select { |m| m._auth_is_group } members |= all_members_of(*groups) unless groups.empty? return members end end end