action_tracker_model.rb
3.53 KB
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
set_table_name 'action_tracker'
belongs_to :user, :polymorphic => true
belongs_to :target, :polymorphic => true
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
named_scope :recent, :conditions => ['created_at >= ?', RECENT_DELAY.days.ago]
named_scope :visible, :conditions => { :visible => true }
def self.current_user_from_model
u = new
u.valid?
u.user
end
def self.update_or_create(params)
u = params[:user] || current_user_from_model
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 = last :conditions => conditions
( !l.nil? and Time.now - l.updated_at < ActionTrackerConfig.timeout ) ? l.update_attributes(params.merge({ :updated_at => Time.now })) : l = new(params)
l
end
def self.add_or_create(params)
u = params[:user] || current_user_from_model
return if u.nil?
target_hash = params[:target].nil? ? {} : {:target_type => params[:target].class.base_class.to_s, :target_id => params[:target].id}
l = last :conditions => { :user_id => u.id, :user_type => u.class.base_class.to_s, :verb => params[:verb].to_s }.merge(target_hash)
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_attributes 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
all(:conditions => 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_eval(&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)
i = -1
send("get_#{param}").collect{ |el| yield(el, i += 1) }
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