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}.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 @assignments = [] @calculated = false add_all_assignments(@subjects) end def add_all_assignments(subjects) @calculated = false if @direction == :down assignments = @assign_class.role_authorizable_eq(*subjects).all(:include => [:subject, {:role => :authorizable}]) @assignments += assignments if @nested subjects_to_search = assignments.collect(&:subject).select { |s| s._auth_is_group } add_all_assignments(subjects_to_search) unless subjects_to_search.empty? end 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 map return self end private def calculate! @assignments = @assignments.uniq @subject_hash = {} @role_link_hash = {} @assignment_links = [] @assignments.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.subject, :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