action_tracker.rb 5.07 KB
require File.join(File.dirname(__FILE__), 'action_tracker_model.rb')

module ActionTracker

  module ControllerMethods

    def self.included(base)
      base.send :user_stamp, ActionTracker::Record
      base.send :extend, ClassMethods
    end
  
    module ClassMethods

      def track_actions_after(verb, options = {}, &block)
        track_actions_by_time(verb, :after, options, &block)
      end
  
      def track_actions_before(verb, options = {}, &block)
        track_actions_by_time(verb, :before, options, &block)
      end
  
      def track_actions(verb, options = {}, &block)
        track_actions_by_time(verb, ActionTrackerConfig.default_filter_time, options, &block)
      end
  
      def track_actions_by_time(verb, time, options = {}, &block)
        keep_params = options.delete(:keep_params) || options.delete('keep_params') || :all
        send("#{time}_filter", options) do |x|
          x.save_action_for_verb(verb.to_s, keep_params)
          block.call(x) unless block.nil?
        end
        send :include, InstanceMethods
      end
    end
  
    module InstanceMethods
      def save_action_for_verb(verb, keep_params = :all)
        if keep_params.is_a? Array
          stored_params = params.reject { |key, value| !keep_params.include?(key.to_sym) and !keep_params.include?(key.to_s) }
        elsif keep_params.to_s == 'none'
          stored_params = {}
        elsif keep_params.to_s == 'all'
          stored_params = params
        end
        user = send ActionTrackerConfig.current_user_method
        tracked_action = case ActionTrackerConfig.verb_type(verb)
          when :groupable
            Record.add_or_create :verb => verb, :user => user, :params => stored_params
          when :updatable
            Record.update_or_create :verb => verb, :user => user, :params => stored_params
          when :single
            Record.new :verb => verb, :user => user, :params => stored_params
        end
        user.tracked_actions << tracked_action
      end
    end

  end

  module ModelMethods

    def self.included(base)
      base.send :extend, ClassMethods
    end
  
    module ClassMethods
      def track_actions(verb, callback, options = {}, &block)
        keep_params = options.delete(:keep_params) || options.delete('keep_params') || :all
        post_proc = options.delete(:post_processing) || options.delete('post_processing') || Proc.new{}
        custom_user = options.delete(:custom_user) || options.delete('custom_user') || nil
        custom_target = options.delete(:custom_target) || options.delete('custom_target') || nil
        send(callback, Proc.new { |tracked| tracked.save_action_for_verb(verb.to_s, keep_params, post_proc, custom_user, custom_target) }, options)
        send :include, InstanceMethods
      end

      def acts_as_trackable(options = {})
        has_many :tracked_actions, { :class_name => "ActionTracker::Record", :order => "updated_at DESC", :foreign_key => :user_id, :dependent => :destroy }.merge(options)
        send :include, InstanceMethods
      end
    end
  
    module InstanceMethods
      def time_spent_doing(verb, conditions = {})
        time = 0
        tracked_actions.all(:conditions => conditions.merge({ :verb => verb.to_s })).each do |t| 
          time += t.updated_at - t.created_at
        end
        time.to_f
      end

      def save_action_for_verb(verb, keep_params = :all, post_proc = Proc.new{}, custom_user = nil, custom_target = nil)
        user = self.send(custom_user) unless custom_user.blank?
        user ||= ActionTracker::Record.current_user_from_model
        target = self.send(custom_target) unless custom_target.blank?
        return nil if user.nil?
        if keep_params.is_a? Array
          stored_params = {}
          keep_params.each do |param|
            result = self
            param.to_s.split('.').each { |m| result = result.send(m) }
            stored_params[param.to_s.gsub(/\./, '_')] = result
          end
        elsif keep_params.to_s == 'none'
          stored_params = {}
        elsif keep_params.to_s == 'all'
          stored_params = self.attributes
        end
        tracked_action = case ActionTrackerConfig.verb_type(verb)
          when :groupable
            Record.add_or_create :verb => verb, :params => stored_params, :user => user, :target => target
          when :updatable
            Record.update_or_create :verb => verb, :params => stored_params, :user => user, :target => target
          when :single
            Record.new :verb => verb, :params => stored_params, :user => user
        end
        tracked_action.target = target || self
        user.tracked_actions << tracked_action
        post_proc.call tracked_action.reload
      end

    end

  end

  module ViewHelper
    def describe(ta)
      "".tap do |result|
        if ta.is_a?(ActionTracker::Record)
          result << ta.description.gsub(/\{\{(.*?)\}\}/) { eval $1 }
        else
          result << ""
        end
      end
    end
  end

end

ActionController::Base.send :include, ActionTracker::ControllerMethods
ActiveRecord::Base.send :include, ActionTracker::ModelMethods
ActionView::Base.send :include, ActionTracker::ViewHelper