app/modules/user/roles_module.rb
module User::RolesModule
def self.included(base)
base.has_many :role_memberships, :include => [:jurisdiction, :role], :dependent => :delete_all
base.has_many :role_requests, :dependent => :delete_all, :include => [:jurisdiction, :role]
base.accepts_nested_attributes_for :role_requests, :organization_membership_requests
base.has_many :roles, :through => :role_memberships, :uniq => true
base.has_many :apps, :through => :roles, :uniq => true, :conditions => "apps.name != 'system'"
base.validates_associated :role_requests
base.validates_associated :role_memberships
base.attr_accessible :role_requests_attributes
base.after_create :assign_public_role
base.scope :with_role, lambda {|role|
role = role.is_a?(Role) ? role : Role.find_by_name(role)
{ :conditions => [ "role_memberships.role_id = ?", role.id ], :include => :role_memberships}
}
base.scope :without_role, lambda {|role|
role = role.is_a?(Role) ? role : Role.find_by_name(role)
{ :conditions => [ "users.id not in (select user_id from role_memberships where role_id = ?)", role.id ], :include => :role_memberships}
}
base.extend(ClassMethods)
end
module ClassMethods
def assign_role(role, jurisdiction, users)
users.each do |u|
u.role_memberships.create(:role => role, :jurisdiction => jurisdiction) unless u.role_memberships.map(&:role_id).include?(role.id) && u.role_memberships.map(&:jurisdiction_id).include?(jurisdiction.id)
end
end
def with_roles(roles)
roles = roles.map{|role| role.is_a?(Role) ? role : Role.find_by_name(role)}
where(["role_memberships.role_id in (?)", roles.map(&:id)]).includes(:role_memberships)
end
def with_apps(app_in)
app_arr = app_in.is_a?(Array) ? app_in : [app_in]
app_arr = app_arr.map{|app| app.is_a?(App) ? app : App.find_by_name(app)}
self.joins(:apps).where("apps.id" => app_arr)
end
alias_method :with_app, :with_apps
end
def is_sysadmin?
return role_memberships.count(:conditions => { :role_id => Role.sysadmin.id } ) > 0
end
def is_super_admin?(app = "")
return true if is_sysadmin?
conditions = app.blank? ? {} : {"apps.name" => app}
return role_memberships.joins(:role => :app).where(['role_id in (?)', Role.superadmins.find(:all, :conditions => conditions).map(&:id)]).count(:conditions => { } ) > 0
end
def is_admin?(app = "")
# TODO: Should be app agnostic
return true if is_sysadmin?
return true if is_super_admin?(app)
conditions = app.blank? ? {} : {"apps.name" => app}
return role_memberships.joins(:role => :app).count( :conditions => { :role_id => Role.admins.find(:all, :conditions => conditions).map(&:id)} ) > 0
end
def is_admin_for?(other, app = "")
# TODO: Role.admin should check on role/app for the jurisdiction
return true if self.is_sysadmin? || self.is_super_admin?
if other.class == Jurisdiction
return true if role_memberships.find(:all, :conditions => {:role_id => Role.admins(app).map(&:id)}).detect{|r| other.is_or_is_descendant_of?(r.jurisdiction)}
elsif other.respond_to?(:each)
other.each do |jurisdiction|
return true if role_memberships.find(:all, :conditions => {:role_id => Role.admins(app).map(&:id)}).detect{|r| jurisdiction.is_or_is_descendant_of?(r.jurisdiction)}
end
end
false
end
def is_org_approver?(app = "phin")
return role_memberships(true).count(:conditions => { :role_id => Role.org_admin(app).id } ) > 0
end
def has_role?(role_sym, app = '')
self.roles.joins(:app).where("roles.name ~* ?", role_sym.to_s.titleize).where(app != "" ? {"apps.name" => app.to_s} : "").exists?
end
def enabled_applications
return current_user.roles.map(&:application).flatten
end
def has_non_public_role?(app = '')
res = self.roles.where(public: false)
res = res.joins(:app).where('apps.name' => app.to_s) unless app.blank?
res.exists?
end
def has_public_role?
self.roles.where(public: true).exists?
end
def has_public_role_in?(jurisdiction)
return role_memberships.count(:conditions => ["role_id = ? AND jurisdiction_id = ?", Role.public.id, j.id]) > 0
end
def has_public_role_request?
return role_requests.count(:conditions => ["role_id = ?", Role.public.id]) > 0
end
def has_app?(app)
self.roles.joins(:app).where("apps.name" => app.to_s).exists?
end
alias_method :has_application?, :has_app?
def visible_actors #this is an ugly solution - returns every user in the system that a given user has rights to see.
return User.without_role("SysAdmin").with_apps( roles.where(name: [Role::Defaults[:admin], Role::Defaults[:superadmin]]).map(&:app).uniq )
end
def alerter?
!role_memberships.alerter.empty?
end
def handle_role_requests(req_json, current_user)
return [ false, [ "Permission denied" ] ] unless editable_by?(current_user)
rq_list = ActiveSupport::JSON.decode(req_json)
result = "success"
rq_errors = []
ActiveRecord::Base.transaction {
rq_list.find_all{|rq| rq["state"]=="deleted" && rq["id"] > 0}.each { |rq|
rqType = (rq["type"]=="req") ? RoleRequest : RoleMembership
rq_to_delete = rqType.find(rq["id"])
if rq_to_delete && self == rq_to_delete.user
rq_to_delete.destroy
else
rq_errors.concat(rq_to_delete.errors.full_messages)
end
}
rq_list.find_all{|rq| rq["state"]=="new"}.each { |rq|
existing_rq = role_requests.find_by_role_id_and_jurisdiction_id(rq["role_id"], rq["jurisdiction_id"])
if existing_rq && current_user.is_admin_for?(self.jurisdictions)
existing_rq.approve!(current_user)
else
role_request = RoleRequest.new
role_request.jurisdiction_id = rq["jurisdiction_id"]
role_request.role_id = rq["role_id"]
role_request.requester = current_user
role_request.user = self
if role_request.valid? && role_request.save
else
result = "failure"
rq_errors.concat(role_request.errors.full_messages)
end
end
}
if self.role_memberships.public_roles.empty?
result = "rollback"
rq_errors.push("You must have at least one public role. Please add a public role and re-save.")
raise ActiveRecord::Rollback
end
}
[ result, rq_errors ]
end
private
def assign_public_role
# If they don't have the phin public role for their home_jurisdiciton, then add it. Rely on the user creator or the "get more apps" manager to add public roles for other apps.
pub = Role.joins(:app).where(public: true, "apps.name" => 'phin').first
self.role_memberships.create(role_id: pub.id, jurisdiction_id: (self.home_jurisdiction || pub.app.root_jurisdiction || Jurisdiction.first).id)
end
end