Skip to content

Instantly share code, notes, and snippets.

@derwiki
Created April 28, 2011 18:52
Show Gist options
  • Select an option

  • Save derwiki/947017 to your computer and use it in GitHub Desktop.

Select an option

Save derwiki/947017 to your computer and use it in GitHub Desktop.
diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index 00e5ce3..3393545 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -61,6 +61,7 @@ class ApplicationController < ActionController::Base
before_filter :activate_email
before_filter :set_p3p_header
before_filter :set_ua_compatible
+ before_filter :track_user
before_filter :redirect_non_www
@@ -174,6 +175,17 @@ class ApplicationController < ActionController::Base
protected
+ def track_user
+ if viewer.real? && params["track"]
+ UserTracking.track!(viewer.id,
+ :tags => params["tags"],
+ :source_type => params["track_source_type"],
+ :source_id => params["track_source_id"])
+ UserTracking.track(viewer.id, "clicked")
+
+ end
+ end
+
# Use this method if you need someone to be authenticated with Facebook on a
# connect page
def require_fbconnect_auth
diff --git a/app/controllers/earn_controller.rb b/app/controllers/earn_controller.rb
index 0b53dfb..bb8d4fc 100644
--- a/app/controllers/earn_controller.rb
+++ b/app/controllers/earn_controller.rb
@@ -55,7 +55,7 @@ class EarnController < ApplicationController
# credit came from cause page
funded_by = Cause.find_by_id(cause_id)
if funded_by
- campaign = funded_by.current_fundraising_campaign
+ campaign = funded_by.current_fundraising_campaign
end
elsif !campaign_id.blank?
# credit came from campaign page, including Clickforcharity
diff --git a/app/controllers/fb/donations_controller.rb b/app/controllers/fb/donations_controller.rb
index 33af886..329c078 100644
--- a/app/controllers/fb/donations_controller.rb
+++ b/app/controllers/fb/donations_controller.rb
@@ -339,6 +339,9 @@ class Fb::DonationsController < Fb::ApplicationController
flash[:email] = params[:email] # unnecessary (email on donation object?)
+ UserTracking.track(viewer.id, "donated",
+ :target => donation)
+
kissmetrics_log_donation(donation)
modesty_log_donation_success
diff --git a/app/models/engagement_credit.rb b/app/models/engagement_credit.rb
index 71a8301..e0b4065 100644
--- a/app/models/engagement_credit.rb
+++ b/app/models/engagement_credit.rb
@@ -177,7 +177,9 @@ class EngagementCredit < ActiveRecord::Base
ActionCredit.record_earn( user, nil, self )
end
-
+ UserTracking.track(self.user_id,
+ "gave a minute",
+ :target => self)
end
PROMO_BANNER_NAME = 'socialvibe_alert_banner'
diff --git a/app/models/user_tracking.rb b/app/models/user_tracking.rb
new file mode 100644
index 0000000..24a8d28
--- /dev/null
+++ b/app/models/user_tracking.rb
@@ -0,0 +1,63 @@
+class UserTracking < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :target, :polymorphic => true
+ belongs_to :source, :polymorphic => true
+
+ validates_presence_of :user_id
+
+ # For activating tracking in outgoing emails
+ def self.track_mails(track=true, options = {})
+ if track
+ options[:track] = 1
+ ActionMailer::Base.default_url_options.merge!(options)
+ else
+ ActionMailer::Base.default_url_options.delete(:track)
+ end
+ end
+
+ TRACK_DURATION = 12.hours
+ def self.track_source(user_id)
+ value = Cacher.get(self.track_key(user_id))
+ end
+ def self.tracked?(user_id, value = nil)
+ value ||= self.track_source(user_id)
+ value && value[:expires] && value[:expires] >= Time.now.to_i
+ end
+ def self.track!(user_id, options = {})
+ expires_in = options[:expires_in]
+ expires_in ||= TRACK_DURATION
+ Cacher.set(self.track_key(user_id), Time.now+expires_in) do
+ result = {:expires => (Time.now+expires_in).to_i}
+
+ [:source_id, :source_type, :tags].each do |key|
+ result[key] = options[key] if options[key]
+ end
+
+ if options[:source]
+ result.merge!({:source_type => options[:source].class.name,
+ :source_id => options[:source].id})
+ end
+ result
+ end
+ end
+ def self.stop_tracking!(user_id)
+ Cacher.delete(self.track_key(user_id))
+ end
+
+ def self.track(user_id, message, options={})
+ value = self.track_source(user_id)
+ return if !self.tracked?(user_id, value)
+
+ logger.info("UserTracking.track user_id: #{user_id} message: #{message}")
+ options.merge!({:user_id => user_id,
+ :source_type => value[:source_type],
+ :source_id => value[:source_id],
+ :message => message})
+ self.create!(options)
+ end
+
+ protected
+ def self.track_key(user_id)
+ "track-user-#{user_id}"
+ end
+end
diff --git a/db/migrate/20110426201659_create_user_trackings.rb b/db/migrate/20110426201659_create_user_trackings.rb
new file mode 100644
index 0000000..565aca2
--- /dev/null
+++ b/db/migrate/20110426201659_create_user_trackings.rb
@@ -0,0 +1,25 @@
+class CreateUserTrackings < ActiveRecord::Migration
+ def self.up
+ create_table :user_trackings do |t|
+ t.column :user_id, :integer
+
+ t.column :source_id, :integer
+ t.column :source_type, :string
+
+ t.column :target_id, :integer
+ t.column :target_type, :string
+
+ t.column :message, :string
+
+ t.datetime :created_at
+ end
+
+ add_index :user_trackings, :user_id
+ add_index :user_trackings, [:source_id, :source_type]
+ add_index :user_trackings, :target_type
+ end
+
+ def self.down
+ drop_table :user_trackings
+ end
+end
diff --git a/db/migrate/20110427184234_user_tracking_tags.rb b/db/migrate/20110427184234_user_tracking_tags.rb
new file mode 100644
index 0000000..b7aa2ad
--- /dev/null
+++ b/db/migrate/20110427184234_user_tracking_tags.rb
@@ -0,0 +1,9 @@
+class UserTrackingTags < ActiveRecord::Migration
+ def self.up
+ add_column :user_trackings, :tags, :string
+ end
+
+ def self.down
+ remove_column :user_trackings, :tags
+ end
+end
diff --git a/test/functional/controllers/earn_controller_testspec.rb b/test/functional/controllers/earn_controller_testspec.rb
index 94793f8..df98f34 100644
--- a/test/functional/controllers/earn_controller_testspec.rb
+++ b/test/functional/controllers/earn_controller_testspec.rb
@@ -67,6 +67,61 @@ context "The earn controller" do
cause.destroy
end
+ specify "should track the user" do
+ Cacher.cache = CACHE
+
+ advertiser = a.EarnAdvertiser.appears
+ advertiser.name = "Supersonic"
+ advertiser.save
+
+ user = a.User.appears
+ cause = a.Cause.appears
+
+ advertiser = EarnAdvertiser.const_get(advertiser.name).find(advertiser.id)
+
+ params = {
+ "activity_id" => "11",
+ "campaign_id" => cause.current_fundraising_campaign.id.to_s,
+ "cause_id" => cause.id.to_s,
+ "network_user_id" => user.anonymous_id,
+ "partner_key" => advertiser.partner_key,
+ "revenue" => "0.077"
+ }
+
+ sig = advertiser.generate_callback_sig(params)
+ params[:sig] = sig
+
+ UserTracking.track!(user.id,
+ :source_type => "Foo",
+ :source_id => 15)
+
+ assert_difference("UserTracking.count") do
+ assert_difference('EngagementCredit.count') do
+ post :credit_callback, params
+ end
+ end
+
+ ec = EngagementCredit.last
+ log_entry = EarnCallbackLog.last
+ ec.funded_by.should == cause
+ ec.campaign.should == cause.current_fundraising_campaign
+ log_entry.response_code.should == "200"
+ log_entry.network_user_id.should == user.anonymous_id
+ assert_response 200
+
+ advertiser.destroy
+ user.destroy
+ cause.destroy
+
+ track = UserTracking.last
+ track.target.should == ec
+ track.source_id.should == 15
+ track.source_type.should == "Foo"
+ track.user_id.should == user.id
+
+ Cacher.cache = nil
+ end
+
# TODO test that invalid signatures are thrown out
specify "should update tracking counters" do
@@ -80,9 +135,9 @@ context "The earn controller" do
old_value = engagement.send(counter)
post :track_engagement_counter, {
- :advertiser_id => advertiser.id,
- :counter => counter,
- :engagement_id => engagement.engagement_id
+ :advertiser_id => advertiser.id,
+ :counter => counter,
+ :engagement_id => engagement.engagement_id
}
engagement.reload
diff --git a/test/functional/controllers/fb/donations_controller_testspec.rb b/test/functional/controllers/fb/donations_controller_testspec.rb
index f1f133c..c7940c7 100644
--- a/test/functional/controllers/fb/donations_controller_testspec.rb
+++ b/test/functional/controllers/fb/donations_controller_testspec.rb
@@ -279,6 +279,59 @@ context 'Submitting a donation form' do
:donation => {:beneficiary_id => Beneficiary.find(:first).id},
:credit_card => {:exp_month => 1}
end
+
+ specify "should track the user" do
+ Cacher.cache = CACHE
+ UserTracking.track!(@cause.creator_id,
+ :source_type => "Foo",
+ :source_id => 15)
+
+ assert_difference('UserTracking.count') do
+ post :create,
+ :cause_id => @cause.id,
+ :donation => {:donor_id => @cause.creator_id,
+ :beneficiary_id => Beneficiary.find(:first).id},
+ :email => @cause.creator.email,
+ :processor => "NFG",
+ :credit_card => {:exp_month => 1}
+ end
+
+ tracking = UserTracking.last
+
+ tracking.user.should == @cause.creator
+ tracking.source_id.should == 15
+ tracking.source_type.should == "Foo"
+ tracking.target.should == Donation.last
+ tracking.message.should == "donated"
+ Cacher.cache = nil
+ end
+
+ specify "should track the user with proper params" do
+ Cacher.cache = CACHE
+
+ # 2 because we also store when the user shows up the 1st time
+ assert_difference('UserTracking.count', 2) do
+ post :create,
+ :track => 1,
+ :track_source_type => "Foo",
+ :track_source_id => 15,
+ :cause_id => @cause.id,
+ :donation => {:donor_id => @cause.creator_id,
+ :beneficiary_id => Beneficiary.find(:first).id},
+ :email => @cause.creator.email,
+ :processor => "NFG",
+ :credit_card => {:exp_month => 1}
+ end
+
+ tracking = UserTracking.last
+
+ tracking.user.should == @cause.creator
+ tracking.source_id.should == 15
+ tracking.source_type.should == "Foo"
+ tracking.target.should == Donation.last
+ tracking.message.should == "donated"
+ Cacher.cache = nil
+ end
end
context 'Viewing donations/new without cause_id' do
diff --git a/test/functional/models/user_tracking_testspec.rb b/test/functional/models/user_tracking_testspec.rb
new file mode 100644
index 0000000..2c5e25d
--- /dev/null
+++ b/test/functional/models/user_tracking_testspec.rb
@@ -0,0 +1,105 @@
+require File.expand_path('../functional_test_helper', File.dirname(__FILE__))
+
+
+context "UserTracking email parsing" do
+ include ActionController::UrlWriter
+ setup do
+ @cause = a.Cause.exists
+ end
+
+ it "Should add proper tags in links" do
+ view = ActionView::Base.new(ActionController::Base.view_paths, {})
+
+ cause_url(@cause).should == "http://test.host/causes/#{@cause.id}"\
+ "-#{@cause.name.parameterize}"
+ UserTracking.track_mails
+ cause_url(@cause).should == "http://test.host/causes/#{@cause.id}"\
+ "-#{@cause.name.parameterize}?track=1"
+
+ UserTracking.track_mails(true,
+ :track_source_id => 14,
+ :track_user_type => "Fool")
+ cause_url(@cause).should == "http://test.host/causes/48-frofrank-"\
+ "cruthunt-fryfryza-shojestyng?track=1&track_source_id=14&"\
+ "track_user_type=Fool"
+ end
+end
+
+context "UserTracking" do
+ setup do
+ @user = a.User.exists
+ Cacher.cache = CACHE
+ UserTracking.stop_tracking!(@user.id)
+ end
+
+ specify "should not track" do
+ assert_no_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something")
+ end
+ end
+
+ specify "should track" do
+ UserTracking.track!(@user.id)
+ assert_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something")
+ end
+ end
+
+ specify "should track with source id" do
+ UserTracking.track!(@user.id,
+ :source_type => "Foo",
+ :source_id => 15)
+ assert_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something")
+ end
+
+ UserTracking.last.source_type.should == "Foo"
+ UserTracking.last.source_id.should == 15
+ end
+
+ specify "should track with source" do
+ UserTracking.track!(@user.id,
+ :source => @user)
+ assert_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something")
+ end
+
+ UserTracking.last.source.should == @user
+ end
+
+ specify "should track with source and target id" do
+ UserTracking.track!(@user.id,
+ :source => @user)
+ assert_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something",
+ :target_type => @user.class.name,
+ :target_id => @user.id)
+ end
+
+ UserTracking.last.source.should == @user
+ UserTracking.last.target.should == @user
+ end
+
+ specify "should track with source and target" do
+ UserTracking.track!(@user.id,
+ :source => @user)
+ assert_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something",
+ :target => @user)
+ end
+
+ UserTracking.last.source.should == @user
+ UserTracking.last.target.should == @user
+ end
+
+ specify "should not track after a while" do
+ UserTracking.track!(@user.id)
+ Time.warp(Time.now+24.hours) do
+ assert_no_difference('UserTracking.count') do
+ UserTracking.track(@user.id, "Tracking something")
+ end
+ end
+ Time.warp(nil)
+ end
+end
+
diff --git a/test/unit/models/earn_engagement_testspec.rb b/test/unit/models/earn_engagement_testspec.rb
index 5bda2d5..1e453a5 100644
--- a/test/unit/models/earn_engagement_testspec.rb
+++ b/test/unit/models/earn_engagement_testspec.rb
@@ -20,7 +20,7 @@ context "An earn engagement" do
value = @engagement.send(name)
EarnEngagement.increment_tracked_counter(name,
- @engagement.earn_advertiser_id, @engagement.engagement_id)
+ @engagement.earn_advertiser_id, @engagement.engagement_id)
@engagement.reload
@engagement.send(name).should == value + 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment