cirandas.net

ref: master

vendor/plugins/action_tracker/lib/action_tracker_model.rb


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module ActionTracker
  class Record < ActiveRecord::Base
    attr_accessible :verb, :params, :user, :target

    self.table_name = 'action_tracker'

    belongs_to :user, :polymorphic => true
    belongs_to :target, :polymorphic => true

    alias :profile :user

    serialize :params, Hash

    before_validation :stringify_verb

    validates_presence_of :verb
    validates_presence_of :user
    validate :user_existence

    def user_existence
      errors.add(:user, "user doesn't exists") if user && !user.class.exists?(user)
    end

    alias_method :subject, :user

    # In days
    RECENT_DELAY = 30

    scope :recent, -> { where 'created_at >= ?', RECENT_DELAY.days.ago }
    scope :visible, -> { where visible: true }

    def self.current_user
      ActionTrackerConfig.current_user.call
    end

    def self.update_or_create(params)
      u = params[:user] || current_user
      return if u.nil?
      target_hash = params[:target].nil? ? {} : {:target_type => params[:target].class.base_class.to_s, :target_id => params[:target].id}
      conditions = { :user_id => u.id, :user_type => u.class.base_class.to_s, :verb => params[:verb].to_s }.merge(target_hash)
      l = where(conditions).last
      ( !l.nil? and Time.now - l.updated_at < ActionTrackerConfig.timeout ) ? l.update(params.merge({ :updated_at => Time.now })) : l = new(params)
      l
    end

    def self.add_or_create(params)
      u = params[:user] || current_user
      return if u.nil?
      target_hash = params[:target].nil? ? {} : {:target_type => params[:target].class.base_class.to_s, :target_id => params[:target].id}
      l = where({user_id: u.id, user_type: u.class.base_class.to_s, verb: params[:verb].to_s}.merge target_hash).last
      if !l.nil? and Time.now - l.created_at < ActionTrackerConfig.timeout
        params[:params].clone.each { |key, value| params[:params][key] = l.params[key].clone.push(value) }
        l.update params
      else
        params[:params].clone.each { |key, value| params[:params][key] = [value] }
        l = new params
      end
      l
    end

    def self.time_spent(conditions = {}) # In seconds
      #FIXME Better if it could be completely done in the database, but SQLite does not support difference between two timestamps
      time = 0
      self.where(conditions).each{ |action| time += action.updated_at - action.created_at }
      time.to_f
    end

    def duration # In seconds
      ( updated_at - created_at ).to_f
    end

    def description
      text = ActionTrackerConfig.get_verb(self.verb)[:description] || ""
      if text.is_a?(Proc)
        self.instance_exec(&text)
      else
        text
      end
    end

    def describe
      description.gsub(/\{\{([^}]+)\}\}/) { eval $1 }
    end

    def predicate
      self.params || {}
    end

    def phrase
      { :subject => self.subject, :verb => self.verb, :predicate => self.predicate }
    end

    def method_missing(method, *args, &block)
      if method.to_s =~ /^get_(.*)$/
        param = method.to_s.gsub('get_', '')
        predicate[param.to_s] || predicate[param.to_sym]
      else
        super
      end
    end

    def collect_group_with_index(param)
      send("get_#{param}").collect.with_index{ |el, i| yield el, i }
    end

    protected

    def validate
      errors.add_to_base "Verb must be one of the following: #{ActionTrackerConfig.verb_names.join(',')}" unless ActionTrackerConfig.verb_names.include?(self.verb)
    end

    private

    def stringify_verb
      self.verb = self.verb.to_s unless self.verb.nil?
    end

  end
end