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 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
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 4
4
+ :patch: 0
5
+
@@ -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
@@ -0,0 +1,3 @@
1
+ # Include hook code here
2
+ require 'has_activity'
3
+ ActiveRecord::Base.send(:include, Elctech::Has::Activity)
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
@@ -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
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_activity do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class HasActivityTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
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