housekeeper-has_activity 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.textile +195 -0
- data/Rakefile +23 -0
- data/VERSION.yml +5 -0
- data/has_activity.gemspec +50 -0
- data/init.rb +3 -0
- data/install.rb +1 -0
- data/lib/core_ext.rb +53 -0
- data/lib/has_activity.rb +232 -0
- data/tasks/has_activity_tasks.rake +4 -0
- data/test/has_activity_test.rb +8 -0
- data/test/test_helper.rb +3 -0
- data/uninstall.rb +1 -0
- metadata +68 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
h1. HasActivity
|
2
|
+
---------------
|
3
|
+
|
4
|
+
* Originally created by Cary Dunn
|
5
|
+
* Modified functionality and additional features by HouseKeeper
|
6
|
+
|
7
|
+
A simple way to grab recent activity or a sum of values on a given model from a table grouped by day, hour,
|
8
|
+
or week with only 1 SQL query and giving the ability to pad the results for days/weeks/hours with no activity.
|
9
|
+
|
10
|
+
The plugin offers the ability to...
|
11
|
+
* Present as a Google Chart (line or bar)
|
12
|
+
* Scope your model to given :conditions
|
13
|
+
* Pad your results for days with no activity
|
14
|
+
* Present your data from a set date until present or between two dates
|
15
|
+
|
16
|
+
NOTE: MySQL only because of date functions use.
|
17
|
+
|
18
|
+
"Example Google Chart Generated":http://chart.apis.google.com/chart?cht=bvs&chs=200x50&chd=t:0,10,15,3,8,4,0,3,2,3,0,11,4,23,14,0,0,0,13,0,4,8,19,10,12,21,1&chco=336699&chbh=a,2&chds=0,23&chf=bg,s,EFEFEF&
|
19
|
+
|
20
|
+
h2. USAGE / INSTALLATION
|
21
|
+
------------------------
|
22
|
+
|
23
|
+
<pre><code>script/plugin install git://github.com/cdunn/has_activity.git</pre></code>
|
24
|
+
|
25
|
+
<pre><code>
|
26
|
+
class Feed < ActiveRecord::Base
|
27
|
+
# Defaults to created_at
|
28
|
+
has_activity
|
29
|
+
|
30
|
+
...
|
31
|
+
end
|
32
|
+
</code></pre>
|
33
|
+
|
34
|
+
<pre><code>
|
35
|
+
class Feed < ActiveRecord::Base
|
36
|
+
# Change the timestamp DB field to something custom
|
37
|
+
has_activity :by => "published_at"
|
38
|
+
|
39
|
+
...
|
40
|
+
end
|
41
|
+
</code></pre>
|
42
|
+
|
43
|
+
<pre><code>
|
44
|
+
# Get all activity since 1 week ago grouped by day (default)
|
45
|
+
Feed.activity_since(1.week.ago)
|
46
|
+
=> [{:activity=>0, :offset=>7, :created_at=>Mon Mar 09 10:27:34 -0700 2009}, {:activity=>0, :offset=>6, :created_at=>Tue Mar 10 10:27:34 -0700 2009}, {:activity=>8, :offset=>5, :created_at=>Wed Mar 11 01:19:09 -0700 2009}, {:activity=>2, :offset=>4, :created_at=>Thu Mar 12 04:26:09 -0700 2009}, {:activity=>0, :offset=>3, :created_at=>Fri Mar 13 10:27:34 -0700 2009}, {:activity=>0, :offset=>2, :created_at=>Sat Mar 14 10:27:34 -0700 2009}, {:activity=>0, :offset=>1, :created_at=>Sun Mar 15 10:27:34 -0700 2009}, {:activity=>0, :offset=>0, :created_at=>Mon Mar 16 10:27:34 -0700 2009}]
|
47
|
+
</code></pre>
|
48
|
+
|
49
|
+
SQL generated for previous statement...
|
50
|
+
<pre><code>
|
51
|
+
SELECT
|
52
|
+
published_at AS timestamp,
|
53
|
+
COUNT(*) AS activity_count,
|
54
|
+
DATEDIFF(now(), published_at) as days_ago
|
55
|
+
FROM feeds
|
56
|
+
WHERE 1=1 AND published_at > '2009-03-09 17:27:33'
|
57
|
+
GROUP BY days_ago
|
58
|
+
ORDER BY published_at ASC
|
59
|
+
</code></pre>
|
60
|
+
|
61
|
+
<pre><code>
|
62
|
+
# Get all activity since 1 day ago grouped by hour scoped to a certain user
|
63
|
+
Feed.activity_since(1.week.ago, :conditions => ["user_id = ?", current_user.id], :group_by => :hour)
|
64
|
+
=> [{:activity=>0, :offset=>24, :created_at=>Sun Mar 15 10:29:47 -0700 2009}, {:activity=>0, :offset=>23, :created_at=>Sun Mar 15 11:29:47 -0700 2009}, {:activity=>0, :offset=>22, :created_at=>Sun Mar 15 12:29:47 -0700 2009}, {:activity=>0, :offset=>21, :created_at=>Sun Mar 15 13:29:47 -0700 2009}, {:activity=>0, :offset=>20, :created_at=>Sun Mar 15 14:29:47 -0700 2009}, {:activity=>0, :offset=>19, :created_at=>Sun Mar 15 15:29:47 -0700 2009}, {:activity=>0, :offset=>18, :created_at=>Sun Mar 15 16:29:47 -0700 2009}, {:activity=>0, :offset=>17, :created_at=>Sun Mar 15 17:29:47 -0700 2009}, {:activity=>0, :offset=>16, :created_at=>Sun Mar 15 18:29:47 -0700 2009}, {:activity=>0, :offset=>15, :created_at=>Sun Mar 15 19:29:47 -0700 2009}, {:activity=>0, :offset=>14, :created_at=>Sun Mar 15 20:29:47 -0700 2009}, {:activity=>0, :offset=>13, :created_at=>Sun Mar 15 21:29:47 -0700 2009}, {:activity=>0, :offset=>12, :created_at=>Sun Mar 15 22:29:47 -0700 2009}, {:activity=>0, :offset=>11, :created_at=>Sun Mar 15 23:29:47 -0700 2009}, {:activity=>0, :offset=>10, :created_at=>Mon Mar 16 00:29:47 -0700 2009}, {:activity=>0, :offset=>9, :created_at=>Mon Mar 16 01:29:47 -0700 2009}, {:activity=>0, :offset=>8, :created_at=>Mon Mar 16 02:29:47 -0700 2009}, {:activity=>0, :offset=>7, :created_at=>Mon Mar 16 03:29:47 -0700 2009}, {:activity=>0, :offset=>6, :created_at=>Mon Mar 16 04:29:47 -0700 2009}, {:activity=>0, :offset=>5, :created_at=>Mon Mar 16 05:29:47 -0700 2009}, {:activity=>0, :offset=>4, :created_at=>Mon Mar 16 06:29:47 -0700 2009}, {:activity=>0, :offset=>3, :created_at=>Mon Mar 16 07:29:47 -0700 2009}, {:activity=>0, :offset=>2, :created_at=>Mon Mar 16 08:29:47 -0700 2009}, {:activity=>0, :offset=>1, :created_at=>Mon Mar 16 09:29:47 -0700 2009}, {:activity=>0, :offset=>0, :created_at=>Mon Mar 16 10:29:47 -0700 2009}]\
|
65
|
+
</code></pre>
|
66
|
+
|
67
|
+
SQL generated for previous statement...
|
68
|
+
<pre><code>
|
69
|
+
SELECT
|
70
|
+
published_at AS timestamp,
|
71
|
+
COUNT(*) AS activity_count,
|
72
|
+
((((YEAR(now()) - YEAR(published_at))*365)+(DAYOFYEAR(now())-DAYOFYEAR(published_at)))*24)+(HOUR(now())-HOUR(published_at)) as hours_ago,
|
73
|
+
CONCAT(YEAR(published_at), CONCAT(DAYOFYEAR(published_at), HOUR(published_at))) AS unique_hour
|
74
|
+
FROM feeds
|
75
|
+
WHERE user_id = 1 AND published_at > '2009-03-15 17:29:47'
|
76
|
+
GROUP BY unique_hour
|
77
|
+
ORDER BY published_at ASC
|
78
|
+
</code></pre>
|
79
|
+
|
80
|
+
<pre><code>
|
81
|
+
# Get all activity since 2 months ago grouped by week and order it from current week to oldest week
|
82
|
+
Feed.activity_since(2.months.ago, :group_by => :week, :order => :desc)
|
83
|
+
=> [{:activity=>0, :offset=>0, :created_at=>Mon Mar 16 10:34:28 -0700 2009}, {:activity=>0, :offset=>1, :created_at=>Mon Mar 09 10:34:28 -0700 2009}, {:activity=>0, :offset=>2, :created_at=>Mon Mar 02 10:34:28 -0800 2009}, {:activity=>0, :offset=>3, :created_at=>Mon Feb 23 10:34:28 -0800 2009}, {:activity=>0, :offset=>4, :created_at=>Mon Feb 16 10:34:28 -0800 2009}, {:activity=>0, :offset=>5, :created_at=>Mon Feb 09 10:34:28 -0800 2009}, {:activity=>0, :offset=>6, :created_at=>Mon Feb 02 10:34:28 -0800 2009}, {:activity=>0, :offset=>7, :created_at=>Mon Jan 26 10:34:28 -0800 2009}, {:activity=>0, :offset=>8, :created_at=>Mon Jan 19 10:34:28 -0800 2009}]
|
84
|
+
</code></pre>
|
85
|
+
|
86
|
+
SQL generated for previous statement...
|
87
|
+
<pre><code>
|
88
|
+
SELECT
|
89
|
+
published_at AS timestamp,
|
90
|
+
COUNT(*) AS activity_count,
|
91
|
+
((YEAR(now()) - YEAR(published_at))*52)+(WEEK(now())-WEEK(published_at)) as weeks_ago,
|
92
|
+
YEARWEEK(published_at) AS unique_week
|
93
|
+
FROM feeds
|
94
|
+
WHERE 1=1 AND published_at > '2009-01-16 17:34:28'
|
95
|
+
GROUP BY unique_week
|
96
|
+
ORDER BY published_at ASC
|
97
|
+
</code></pre>
|
98
|
+
|
99
|
+
<pre><code>
|
100
|
+
# Get Usd Net Commission in July ago grouped by day and order it in ascending order by the days commission was earnt on for account_id 1
|
101
|
+
AccountPnl.activity_between(july_month.beginning_of_month,
|
102
|
+
july_month.end_of_month,
|
103
|
+
:group_by => :day,
|
104
|
+
:padding => false,
|
105
|
+
:sum_on => "usd_net_commission",
|
106
|
+
:conditions => ["crm_account_id=?", 1],
|
107
|
+
:order => :asc)
|
108
|
+
</code></pre>
|
109
|
+
|
110
|
+
SQL generated for previous statement...
|
111
|
+
<pre><code>
|
112
|
+
SELECT
|
113
|
+
earnt_on AS timestamp,
|
114
|
+
COUNT(*) AS activity_count, SUM(usd_net_commission) as sum,
|
115
|
+
DATEDIFF('2009-07-31 23:59:59', earnt_on) as days_ago
|
116
|
+
FROM crm_daily_account_pnls
|
117
|
+
WHERE crm_account_id=16 AND earnt_on
|
118
|
+
BETWEEN '2009-07-01 00:00:00' AND '2009-07-31 23:59:59'
|
119
|
+
GROUP BY days_ago
|
120
|
+
ORDER BY earnt_on ASC
|
121
|
+
</code></pre>
|
122
|
+
|
123
|
+
|
124
|
+
h2. CONVERT DATA INTO GOOGLE CHART
|
125
|
+
|
126
|
+
<pre><code>
|
127
|
+
Feed.activity_since(6.months.ago, :group_by => :week, :order => :desc).to_activity_gchart
|
128
|
+
=> "http://chart.apis.google.com/chart?cht=bvs&chs=200x50&chd=t:0,10,15,3,8,4,0,3,2,3,0,11,4,23,14,0,0,0,13,0,4,8,19,10,12,21,1&chco=336699&chbh=a,2&chds=0,23&chf=bg,s,EFEFEF&"
|
129
|
+
</code></pre>
|
130
|
+
|
131
|
+
<pre><code>
|
132
|
+
Feed.activity_since(6.months.ago, :group_by => :week, :order => :desc).to_activity_gchart
|
133
|
+
AccountPnl.activity_between(july_month.beginning_of_month,
|
134
|
+
july_month.end_of_month,
|
135
|
+
:group_by => :day,
|
136
|
+
:padding => false,
|
137
|
+
:sum_on => "usd_net_commission",
|
138
|
+
:conditions => ["crm_account_id=?", 1],
|
139
|
+
:order => :asc).to_activity_gchart( :type => :line,
|
140
|
+
:column => :sum,
|
141
|
+
:size => "100x45",
|
142
|
+
:bgcolor => "f0ffdc",
|
143
|
+
:chart_color => "D1EAFF",
|
144
|
+
:area_color => "DFEBFF",
|
145
|
+
:line_color => "c7c7c7",
|
146
|
+
:line_width => "4"))
|
147
|
+
=> "http://chart.apis.google.com/chart?chs=100x45&cht=ls&chco=c7c7c7&chm=B,DFEBFF,0,0,0&chd=t:<data>&chds=0,0&chf=bg,s,f0ffdc&"
|
148
|
+
</code></pre>
|
149
|
+
|
150
|
+
h2. OTHER OPTIONS
|
151
|
+
|
152
|
+
<pre><code>
|
153
|
+
# Grabs a hash of the activity since <time ago> grouped by <hour/day/week>
|
154
|
+
#
|
155
|
+
# * :conditions
|
156
|
+
# same as the standard Rails finder. Used to scope your activity to a particular user, etc.
|
157
|
+
# * :padding
|
158
|
+
# true/false
|
159
|
+
# * :group_by
|
160
|
+
# :hour, :day, :week
|
161
|
+
#
|
162
|
+
def activity_since(since=1.week.ago, options={})
|
163
|
+
</code></pre>
|
164
|
+
|
165
|
+
<pre><code>
|
166
|
+
# Returns a URL to a simple google chart the represents the activity returned by the plugin
|
167
|
+
#
|
168
|
+
# * :type => :bar/:line
|
169
|
+
# * :size => "200x50"
|
170
|
+
# * :bgcolor => "EFEFEF"
|
171
|
+
# * :chart_color => "336699"
|
172
|
+
# * :area_color => "DFEBFF" (only for :line)
|
173
|
+
# * :line_color => "0077CC" (only for :line)
|
174
|
+
# * :line_width => "2" (only for :line)
|
175
|
+
#
|
176
|
+
def to_activity_gchart(options={})
|
177
|
+
</code></pre>
|
178
|
+
|
179
|
+
h2. INDEX THE TIMESTAMP YOU USE
|
180
|
+
|
181
|
+
Obviously there is not "one index fits all" but you should include an index on at least the timestamp that fits the conditions you are using.
|
182
|
+
The same applies when performing SUM on a column.
|
183
|
+
<pre><code>
|
184
|
+
add_index :model, [:created_at]
|
185
|
+
</code></pre>
|
186
|
+
|
187
|
+
h2. NOTES
|
188
|
+
|
189
|
+
* Using sum and creating Bar Charts is not fully tested - HouseKeeper
|
190
|
+
* Some work still needs to be done on the queries and a tidy up of has_activity.rb
|
191
|
+
|
192
|
+
Copyright (c) 2009 Cary Dunn <cary.dunn@gmail.com> "http://elctech.com":http://elctech.com, released under the MIT license
|
193
|
+
Modified by HouseKeeper
|
194
|
+
- Added the ability to sum a column - giving you a total ammount from a date until now or between 2 dates
|
195
|
+
- Added Between functionality so you can get activity or sums between 2 specified dates
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the has_activity plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the has_activity plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'HasActivity'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{has_activity}
|
5
|
+
s.version = "0.4.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Cary Dunn", "Carl Burton"]
|
9
|
+
s.date = %q{2009-09-17}
|
10
|
+
s.description = %q{A simple way to grab recent activity or a columns sum on a given model from a table grouped by day, hour, or week with only 1 SQL query and giving the ability to pad the results for days/weeks/hours with no activity.}
|
11
|
+
s.email = %q{carl@house-keeping.com}
|
12
|
+
s.extra_rdoc_files = [
|
13
|
+
"README.textile"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
"VERSION.yml",
|
17
|
+
"uninstall.rb",
|
18
|
+
"README.textile",
|
19
|
+
"Rakefile",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"install.rb",
|
22
|
+
"init.rb",
|
23
|
+
"has_activity.gemspec",
|
24
|
+
"test/test_helper.rb",
|
25
|
+
"test/has_activity_test.rb",
|
26
|
+
"tasks/has_activity_tasks.rake",
|
27
|
+
"lib/has_activity.rb",
|
28
|
+
"lib/core_ext.rb"
|
29
|
+
]
|
30
|
+
s.has_rdoc = false
|
31
|
+
s.homepage = %q{http://github.com/housekeeper/has_activity}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.1}
|
35
|
+
s.summary = %q{A simple way to grab recent activity or a columns sum on a given model from a table grouped by day, hour, or week with only 1 SQL query and giving the ability to pad the results for days/weeks/hours with no activity.}
|
36
|
+
s.test_files = [
|
37
|
+
"test/test_helper.rb",
|
38
|
+
"test/has_activity_test.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 2
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
|
+
else
|
47
|
+
end
|
48
|
+
else
|
49
|
+
end
|
50
|
+
end
|
data/init.rb
ADDED
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
data/lib/core_ext.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Original Author Cary Dunn <cary.dunn@gmail.com>
|
2
|
+
# Modified by HouseKeeper
|
3
|
+
|
4
|
+
unless Array.instance_methods.include? 'to_activity_gchart'
|
5
|
+
Array.class_eval do
|
6
|
+
# Returns a URL to a simple google chart the represents the activity returned by the plugin
|
7
|
+
#
|
8
|
+
# * :type => :bar/:line
|
9
|
+
# * :column => :activity/:sum
|
10
|
+
# * :size => "200x50"
|
11
|
+
# * :bgcolor => "EFEFEF"
|
12
|
+
# * :chart_color => "336699"
|
13
|
+
# * :area_color => "DFEBFF" (only for :line)
|
14
|
+
# * :line_color => "0077CC" (only for :line)
|
15
|
+
# * :line_width => "2" (only for :line)
|
16
|
+
#
|
17
|
+
def to_activity_gchart(options={})
|
18
|
+
options[:type] ||= :graph
|
19
|
+
options[:column] ||= :activity
|
20
|
+
options[:size] ||= "200x50"
|
21
|
+
options[:bgcolor] ||= "EFEFEF"
|
22
|
+
options[:chart_color] ||= "336699"
|
23
|
+
options[:area_color] ||= "DFEBFF"
|
24
|
+
options[:line_color] ||= "0077CC"
|
25
|
+
options[:line_width] ||= "2"
|
26
|
+
|
27
|
+
case options[:column]
|
28
|
+
when :activity
|
29
|
+
activity_min_data_point = self.min{|a,b| a[:activity] <=> b[:activity] }[:activity]
|
30
|
+
activity_max_data_point = self.max{|a,b| a[:activity] <=> b[:activity] }[:activity]
|
31
|
+
activity_str = self.map{|a| a[:activity]}.join(",")
|
32
|
+
return generate_url(activity_str, activity_min_data_point, activity_max_data_point, options)
|
33
|
+
when :sum
|
34
|
+
sum_min_data_point = self.min{|a,b| a[:sum] <=> b[:sum] }[:sum]
|
35
|
+
sum_max_data_point = self.max{|a,b| a[:sum] <=> b[:sum] }[:sum]
|
36
|
+
sum_str = self.map{|a| a[:sum]}.join(",")
|
37
|
+
return generate_url(sum_str, sum_min_data_point, sum_max_data_point, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def generate_url(data, min_data_point, max_data_point, options={})
|
45
|
+
if options[:type] == :line
|
46
|
+
return "http://chart.apis.google.com/chart?chs=#{options[:size]}&cht=ls&chco=#{options[:line_color]}&chm=B,#{options[:area_color]},0,0,0&chd=t:#{data}&chds=#{min_data_point},#{max_data_point}&chf=bg,s,#{options[:bgcolor]}&"
|
47
|
+
else
|
48
|
+
return "http://chart.apis.google.com/chart?cht=bvs&chs=#{options[:size]}&chd=t:#{data}&chco=#{options[:chart_color]}&chbh=a,#{options[:line_width]}&chds=#{min_data_point},#{max_data_point}&chf=bg,s,#{options[:bgcolor]}&"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/has_activity.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
#
|
2
|
+
# => has_activity
|
3
|
+
# => Cary Dunn <cary.dunn@gmail.com>
|
4
|
+
# => Modified by HouseKeeper: added between methods and sum option
|
5
|
+
|
6
|
+
# HasActivity
|
7
|
+
|
8
|
+
require 'core_ext'
|
9
|
+
|
10
|
+
module Elctech
|
11
|
+
module Has #:nodoc:
|
12
|
+
module Activity #:nodoc:
|
13
|
+
def self.included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
def self.extended(base)
|
20
|
+
base.class_inheritable_accessor :activity_options
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_activity(options={})
|
24
|
+
options[:by] ||= "created_at"
|
25
|
+
include Elctech::Has::Activity::InstanceMethods
|
26
|
+
extend Elctech::Has::Activity::SingletonMethods
|
27
|
+
|
28
|
+
self.activity_options = options
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module SingletonMethods
|
33
|
+
|
34
|
+
# Grabs a hash of the activity between <time a> AND <time b>grouped by <hour/day/week>
|
35
|
+
#
|
36
|
+
# * :conditions
|
37
|
+
# same as the standard Rails finder. Used to scope your activity to a particular user, etc.
|
38
|
+
# * :padding
|
39
|
+
# true/false
|
40
|
+
# * :group_by
|
41
|
+
# :hour, :day, :week
|
42
|
+
#
|
43
|
+
def activity_between(between=1.week.ago, andbetween=Time.now.utc, options={})
|
44
|
+
activity_scope = (options.has_key?(:conditions) ? sanitize_sql(options[:conditions]) : "1=1")
|
45
|
+
options[:padding] ||= true
|
46
|
+
options[:order] ||= :asc
|
47
|
+
options[:group_by] ||= :day
|
48
|
+
sum = options[:sum_on] ? "SUM(#{options[:sum_on]}) as sum," : ""
|
49
|
+
|
50
|
+
case options[:group_by]
|
51
|
+
when :hour
|
52
|
+
sql_statement = sanitize_sql(
|
53
|
+
["SELECT
|
54
|
+
#{activity_options[:by]} AS timestamp,
|
55
|
+
COUNT(*) AS activity_count, #{sum}
|
56
|
+
((((YEAR(now()) - YEAR(#{activity_options[:by]}))*365)+(DAYOFYEAR(now())-DAYOFYEAR(#{activity_options[:by]})))*24)+(HOUR(now())-HOUR(#{activity_options[:by]})) as hours_ago,
|
57
|
+
CONCAT(YEAR(#{activity_options[:by]}), CONCAT(DAYOFYEAR(#{activity_options[:by]}), HOUR(#{activity_options[:by]}))) AS unique_hour
|
58
|
+
FROM #{self.table_name}
|
59
|
+
WHERE #{activity_scope} AND #{activity_options[:by]} > ?
|
60
|
+
GROUP BY unique_hour
|
61
|
+
ORDER BY #{activity_options[:by]} ASC",
|
62
|
+
between.to_s(:db)
|
63
|
+
]
|
64
|
+
)
|
65
|
+
unit = "hours_ago"
|
66
|
+
oldest_possible_unit = ((andbetween-between)/60)/60
|
67
|
+
when :week
|
68
|
+
sql_statement = sanitize_sql(
|
69
|
+
["SELECT
|
70
|
+
#{activity_options[:by]} AS timestamp,
|
71
|
+
COUNT(*) AS activity_count, #{sum}
|
72
|
+
((YEAR(now()) - YEAR(#{activity_options[:by]}))*52)+(WEEK(now())-WEEK(#{activity_options[:by]})) as weeks_ago,
|
73
|
+
YEARWEEK(#{activity_options[:by]}) AS unique_week
|
74
|
+
FROM #{self.table_name}
|
75
|
+
WHERE #{activity_scope} AND #{activity_options[:by]}
|
76
|
+
BETWEEN ? AND ?
|
77
|
+
GROUP BY unique_week
|
78
|
+
ORDER BY #{activity_options[:by]} ASC",
|
79
|
+
between.to_s(:db),andbetween.to_s(:db)
|
80
|
+
]
|
81
|
+
)
|
82
|
+
unit = "weeks_ago"
|
83
|
+
oldest_possible_unit = ((((andbetween-between)/60)/60)/24)/7
|
84
|
+
else
|
85
|
+
sql_statement = sanitize_sql(
|
86
|
+
["SELECT
|
87
|
+
#{activity_options[:by]} AS timestamp,
|
88
|
+
COUNT(*) AS activity_count, #{sum}
|
89
|
+
DATEDIFF('#{andbetween.to_s(:db)}', #{activity_options[:by]}) as days_ago
|
90
|
+
FROM #{self.table_name}
|
91
|
+
WHERE #{activity_scope} AND #{activity_options[:by]}
|
92
|
+
BETWEEN ? AND ?
|
93
|
+
GROUP BY days_ago
|
94
|
+
ORDER BY #{activity_options[:by]} ASC",
|
95
|
+
between.to_s(:db), andbetween.to_s(:db)
|
96
|
+
]
|
97
|
+
)
|
98
|
+
unit = "days_ago"
|
99
|
+
oldest_possible_unit = (((andbetween-between)/60)/60)/24
|
100
|
+
end
|
101
|
+
|
102
|
+
results = connection.select_all(sql_statement)
|
103
|
+
(options[:padding] ? pad_activity_results(results, unit, oldest_possible_unit.round, options[:order]) : format_activity_results(results, unit, order))
|
104
|
+
end
|
105
|
+
|
106
|
+
# Grabs a hash of the activity since <time ago> grouped by <hour/day/week>
|
107
|
+
#
|
108
|
+
# * :conditions
|
109
|
+
# same as the standard Rails finder. Used to scope your activity to a particular user, etc.
|
110
|
+
# * :padding
|
111
|
+
# true/false
|
112
|
+
# * :group_by
|
113
|
+
# :hour, :day, :week
|
114
|
+
#
|
115
|
+
def activity_since(since=1.week.ago, options={})
|
116
|
+
activity_scope = (options.has_key?(:conditions) ? sanitize_sql(options[:conditions]) : "1=1")
|
117
|
+
options[:padding] ||= true
|
118
|
+
options[:order] ||= :asc
|
119
|
+
options[:group_by] ||= :day
|
120
|
+
sum = options[:sum_on] ? "SUM(#{options[:sum_on]}) as sum," : ""
|
121
|
+
|
122
|
+
case options[:group_by]
|
123
|
+
when :hour
|
124
|
+
sql_statement = sanitize_sql(
|
125
|
+
["SELECT
|
126
|
+
#{activity_options[:by]} AS timestamp,
|
127
|
+
COUNT(*) AS activity_count, #{sum}
|
128
|
+
((((YEAR(now()) - YEAR(#{activity_options[:by]}))*365)+(DAYOFYEAR(now())-DAYOFYEAR(#{activity_options[:by]})))*24)+(HOUR(now())-HOUR(#{activity_options[:by]})) as hours_ago,
|
129
|
+
CONCAT(YEAR(#{activity_options[:by]}), CONCAT(DAYOFYEAR(#{activity_options[:by]}), HOUR(#{activity_options[:by]}))) AS unique_hour
|
130
|
+
FROM #{self.table_name}
|
131
|
+
WHERE #{activity_scope} AND #{activity_options[:by]} > ?
|
132
|
+
GROUP BY unique_hour
|
133
|
+
ORDER BY #{activity_options[:by]} ASC",
|
134
|
+
since.to_s(:db)
|
135
|
+
]
|
136
|
+
)
|
137
|
+
unit = "hours_ago"
|
138
|
+
oldest_possible_unit = ((Time.now-since)/60)/60
|
139
|
+
when :week
|
140
|
+
sql_statement = sanitize_sql(
|
141
|
+
["SELECT
|
142
|
+
#{activity_options[:by]} AS timestamp,
|
143
|
+
COUNT(*) AS activity_count, #{sum}
|
144
|
+
((YEAR(now()) - YEAR(#{activity_options[:by]}))*52)+(WEEK(now())-WEEK(#{activity_options[:by]})) as weeks_ago,
|
145
|
+
YEARWEEK(#{activity_options[:by]}) AS unique_week
|
146
|
+
FROM #{self.table_name}
|
147
|
+
WHERE #{activity_scope} AND #{activity_options[:by]} > ?
|
148
|
+
GROUP BY unique_week
|
149
|
+
ORDER BY #{activity_options[:by]} ASC",
|
150
|
+
since.to_s(:db)
|
151
|
+
]
|
152
|
+
)
|
153
|
+
unit = "weeks_ago"
|
154
|
+
oldest_possible_unit = ((((Time.now-since)/60)/60)/24)/7
|
155
|
+
else
|
156
|
+
sql_statement = sanitize_sql(
|
157
|
+
["SELECT
|
158
|
+
#{activity_options[:by]} AS timestamp,
|
159
|
+
COUNT(*) AS activity_count, #{sum}
|
160
|
+
DATEDIFF(now(), #{activity_options[:by]}) as days_ago
|
161
|
+
FROM #{self.table_name}
|
162
|
+
WHERE #{activity_scope} AND #{activity_options[:by]} > ?
|
163
|
+
GROUP BY days_ago
|
164
|
+
ORDER BY #{activity_options[:by]} ASC",
|
165
|
+
since.to_s(:db)
|
166
|
+
]
|
167
|
+
)
|
168
|
+
unit = "days_ago"
|
169
|
+
oldest_possible_unit = (((Time.now-since)/60)/60)/24
|
170
|
+
end
|
171
|
+
|
172
|
+
results = connection.select_all(sql_statement)
|
173
|
+
(options[:padding] ? pad_activity_results(results, unit, oldest_possible_unit.round, options[:order]) : format_activity_results(results, unit, order))
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
def format_activity_results(results, unit, order)
|
178
|
+
results.inject([]) do |rs,r|
|
179
|
+
entry = {
|
180
|
+
:offset => r[unit].to_i,
|
181
|
+
:activity => r["activity_count"].to_i,
|
182
|
+
:sum => r["sum"].to_f,
|
183
|
+
:date => Time.parse(r["timestamp"])
|
184
|
+
}
|
185
|
+
(order == :asc) ? rs.push(entry) : rs.unshift(entry)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def pad_activity_results(results, unit, oldest_possible_offset, order)
|
190
|
+
padded_results = []
|
191
|
+
|
192
|
+
current_unit_offset = oldest_possible_offset
|
193
|
+
current_result_index = 0
|
194
|
+
|
195
|
+
while current_unit_offset >= 0 do
|
196
|
+
if current_result_index < results.size && results[current_result_index][unit].to_i == current_unit_offset
|
197
|
+
entry = {
|
198
|
+
:offset => current_unit_offset,
|
199
|
+
:activity => results[current_result_index]["activity_count"].to_i,
|
200
|
+
:sum => results[current_result_index]["sum"].to_f,
|
201
|
+
:created_at => Time.parse(results[current_result_index]["timestamp"])
|
202
|
+
}
|
203
|
+
current_result_index = current_result_index+1
|
204
|
+
else
|
205
|
+
case unit
|
206
|
+
when "hours_ago"
|
207
|
+
created_at_given_offset = Time.now-current_unit_offset.hours
|
208
|
+
when "weeks_ago"
|
209
|
+
created_at_given_offset = Time.now-current_unit_offset.weeks
|
210
|
+
else
|
211
|
+
created_at_given_offset = Time.now-current_unit_offset.days
|
212
|
+
end
|
213
|
+
entry = {
|
214
|
+
:offset => current_unit_offset,
|
215
|
+
:activity => 0,
|
216
|
+
:sum => 0,
|
217
|
+
:created_at => created_at_given_offset
|
218
|
+
}
|
219
|
+
end
|
220
|
+
current_unit_offset = current_unit_offset-1
|
221
|
+
(order == :asc) ? padded_results.push(entry) : padded_results.unshift(entry)
|
222
|
+
end
|
223
|
+
|
224
|
+
padded_results
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
module InstanceMethods;end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
data/test/test_helper.rb
ADDED
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: housekeeper-has_activity
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cary Dunn
|
8
|
+
- Carl Burton
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-09-17 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: A simple way to grab recent activity or a columns sum on a given model from a table grouped by day, hour, or week with only 1 SQL query and giving the ability to pad the results for days/weeks/hours with no activity.
|
18
|
+
email: carl@house-keeping.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README.textile
|
25
|
+
files:
|
26
|
+
- VERSION.yml
|
27
|
+
- uninstall.rb
|
28
|
+
- README.textile
|
29
|
+
- Rakefile
|
30
|
+
- MIT-LICENSE
|
31
|
+
- install.rb
|
32
|
+
- init.rb
|
33
|
+
- has_activity.gemspec
|
34
|
+
- test/test_helper.rb
|
35
|
+
- test/has_activity_test.rb
|
36
|
+
- tasks/has_activity_tasks.rake
|
37
|
+
- lib/has_activity.rb
|
38
|
+
- lib/core_ext.rb
|
39
|
+
has_rdoc: false
|
40
|
+
homepage: http://github.com/housekeeper/has_activity
|
41
|
+
licenses:
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: A simple way to grab recent activity or a columns sum on a given model from a table grouped by day, hour, or week with only 1 SQL query and giving the ability to pad the results for days/weeks/hours with no activity.
|
66
|
+
test_files:
|
67
|
+
- test/test_helper.rb
|
68
|
+
- test/has_activity_test.rb
|