module Petergate module ActionController module Base module ClassMethods def const_missing(const_name) if [:AllRest, :ALLREST].include?(const_name) warn "`AllRest` and `ALLREST` has been deprecated. Use :all instead." return ALLRESTDEP else return super end end def all_actions ->{self.action_methods.to_a.map(&:to_sym) - [:check_access, :title]}.call end def except_actions(arr = []) all_actions - arr end def access(rules = {}, &block) if block b_rules = block.call rules = rules.merge(b_rules) if b_rules.is_a?(Hash) end instance_eval do @_controller_rules = rules @_controller_message = rules.delete(:message) def controller_rules @_controller_rules end def controller_message @_controller_message || "Permission Denied" end def inherited(subclass) subclass.instance_variable_set("@_controller_rules", instance_variable_get("@_controller_rules")) subclass.instance_variable_set("@_controller_message", instance_variable_get("@_controller_message")) end end before_action do unless logged_in?(:root_admin) message = permissions(self.class.controller_rules) if message == false || message.is_a?(String) if current_user || @user forbidden! message else unauthorized! end end end end end end ALLRESTDEP = [:show, :index, :new, :edit, :update, :create, :destroy] def self.included(base) base.extend(ClassMethods) base.helper_method :logged_in?, :forbidden!, :unauthorized! end def parse_permission_rules(rules) rules = rules.inject({}) do |h, (k, v)| special_values = case v.class.to_s when "Symbol" v == :all ? self.class.all_actions : raise("No action for: #{v}") when "Hash" v[:except].present? ? self.class.except_actions(v[:except]) : raise("Invalid values for except: #{v.values}") when "Array" v else raise("No action for: #{v}") end h.merge({k => special_values}) end # Allows Array's of keys for he same hash. rules = rules.inject({}){|h, (k, v)| k.class == Array ? h.merge(Hash[k.map{|kk| [kk, v]}]) : h.merge(k => v) } end def permissions(rules = {all: [:index, :show], customer: [], wiring: []}) rules = parse_permission_rules(rules) allowances = [rules[:all]] current_user.roles.each do |role| allowances << rules[role] end if user_logged_in? allowances.flatten.compact.include?(action_name.to_sym) end def logged_in?(*roles) current_user && current_user.has_roles?(*roles) end def user_logged_in? !!current_user end def custom_message defined?(self.class.controller_message) ? self.class.controller_message : 'Permission Denied' end def unauthorized! respond_to do |format| format.any(:js, :json, :xml) { render nothing: true, status: :unauthorized } format.html do authenticate_user! end end end def forbidden!(msg = nil) respond_to do |format| format.any(:js, :json, :xml) { render nothing: true, status: :forbidden } format.html do destination = current_user.present? ? request.referrer || after_sign_in_path_for(current_user) : root_path redirect_to destination, notice: (msg || custom_message) end end end end end end class ActionController::Base include Petergate::ActionController::Base end