module RulesEngine module ControllerUsers ######### Requires the following paths ######### root_path USER_ACCESS_LEVEL = [ ["Administrator", User::ACCESS_LEVEL_ADMIN], ["Account Disabled", User::ACCESS_LEVEL_DISABLED] ] # Inclusion hook to make #current_user #logged_in? and #logged_in_as_admin? # available as ActionView helper methods. def self.included(base) base.send :helper_method, :current_user, :logged_in?, :logged_in_as_admin?, :logged_in_disabled?, :user_access_level, :user_access_levels base.send :before_filter, :set_timezone base.class_eval do extend ClassMethods end end # Accesses the current user from the session. # Future calls avoid the database because nil is not equal to false. def current_user return nil if @current_user == false @current_user || (login_from_session || login_from_basic_auth || login_from_cookie) @current_user || nil end # Returns true or false if the user is logged in. # Preloads @current_user with the user model if they're logged in. def logged_in? !!current_user end def logged_in_as_admin? logged_in? && current_user.access_level == User::ACCESS_LEVEL_ADMIN end def logged_in_disabled? logged_in? && current_user.access_level == User::ACCESS_LEVEL_DISABLED end def login_required unless logged_in? flash[:error]="This page requires you to login" access_denied end end def admin_access_required login_required return unless logged_in? unless current_user.access_level == User::ACCESS_LEVEL_ADMIN flash[:error]="This page requires administrator access" user_access_denied end end def user_access_level(user) match = USER_ACCESS_LEVEL.find {|value| value[1] == user.access_level} match.nil? ? "unknown" : match[0] end def user_access_levels USER_ACCESS_LEVEL.sort {|a, b| a[1] <=> b[1]} end def set_timezone Time.zone = logged_in? ? current_user.time_zone : "Eastern Time (US & Canada)" end module ClassMethods def define_access_level name, access_level (class << self; self end).instance_eval do USER_ACCESS_LEVEL << [name.to_s.titleize, access_level] end (class << ActionController::Base; self end).instance_eval do define_method "#{name}_access_level" do access_level end end define_method "logged_in_as_#{name}?" do logged_in? && current_user.access_level >= access_level end define_method "#{name}_access_required" do login_required return unless logged_in? unless current_user.access_level >= access_level flash[:error]="This page requires #{name} access" user_access_denied end end self.send :helper_method, "logged_in_as_#{name}" end end protected # Store the given user id in the session. def current_user=(new_user) session[:user_id] = new_user ? new_user.id : nil @current_user = new_user || false # store false end def access_denied respond_to do |format| format.html do session[:return_to] = request.request_uri redirect_to user_login_path return end format.js do render :update do |page| page << "window.location.href = '#{user_login_path}';" end end # format.any do # request_http_basic_authentication 'Web Password' # end # end end end def user_access_denied respond_to do |format| format.html do redirect_to root_path end format.js do render :update do |page| page << "window.location.href = '#{root_path}';" end end # format.any do # request_http_basic_authentication 'Web Password' # end end end # Called from #current_user. First attempt to login by the user id stored in the session. def login_from_session self.current_user = User.find_by_id(session[:user_id]) if session[:user_id] end # Called from #current_user. Now, attempt to login by basic authentication information. def login_from_basic_auth authenticate_with_http_basic do |name, password| self.current_user = User.authenticate_by_login(name, password) || User.authenticate_by_email(name, password) end end # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie. def login_from_cookie user = cookies[:auth_token] && User.authenticate_by_remember_token(cookies[:auth_token]) if user cookies[:auth_token] = { :value => user.remember_token, :expires => user.remember_token_expires_at } self.current_user = user end end end end ActionController::Base.class_eval do include RulesEngine::ControllerUsers end