action_tracker_model.rb
4.06 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
module ActionTracker
class Record < ActiveRecord::Base
extend CacheCounterHelper
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
after_create do |record|
update_cache_counter(:activities_count, record.user, 1)
if record.target.kind_of?(Organization)
update_cache_counter(:activities_count, record.target, 1)
end
end
after_destroy do |record|
if record.created_at >= RECENT_DELAY.days.ago
update_cache_counter(:activities_count, record.user, -1)
if record.target.kind_of?(Organization)
update_cache_counter(:activities_count, record.target, -1)
end
end
end
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