module Warrant module App module Models module Warrantable def self.included(model) model.extend(ClassMethods) model.class_eval do class << self alias_method :find_without_warrant, :find unless method_defined?(:find_without_warrant) alias_method :find, :find_with_warrant # alias_method_chain :find, :warrant end # after_find taxes performance before_create :warrant!, :unless => lambda { self.create? } before_update :warrant!, :unless => lambda { self.update? } before_destroy :warrant!, :unless => lambda { self.destroy? } def create? self.class.create? end def find? self.class.find? end alias_method :read?, :find? def update? self.class.update? || self.related_to_current_user? end def destroy? self.class.destroy? || self.related_to_current_user? end # TODO memoize ??? def related_to_current_user? return false unless self.current_user self.current_user == self || self.respond_to?('user') && self.current_user == self.user || self.respond_to?('users') && self.users.include?(self.current_user) end def warrant! raise Warrant::AuthorizationError end end end module ClassMethods def find_with_warrant(*args) found = find_without_warrant(*args) found = case when found.is_a?(Array) ; found.delete_if {|r| !r.find? } when !found.find? ; found.warrant! else found end end def create? true end def find? true end alias_method :read?, :find? # TODO alias as find? def update? false end def destroy? false end # obscure :title, :with => 'shhhhh', :if => :not_cool? # obscure :title, :with => :sekret, :unless => :cool? # obscure :title, :unless => :cool? def obscure(attribute, opts={}) opts[:with] ||= nil opts.delete(:unless) if opts.key?(:if) # only one conditional allowed # TODO error unless attribute exists # raise Warrant::AuthorizationError unless send(:instance_variable_get, :@attributes).include?(attribute.to_s) define_method(attribute.to_sym) do if ( opts.key?(:if) && send(opts[:if]) ) || # :if is specified and evaluates true ( opts.key?(:unless) && !send(opts[:unless]) ) || # :unless is specified and evaluates false ( !opts.key?(:if) && !opts.key?(:unless) ) # no conditional is specified opts[:with].is_a?(Symbol) ? send(opts[:with]) : opts[:with] else # return value of instance variable send(:instance_variable_get, :@attributes)[attribute.to_s] end end end end end end end end