email_tracker 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{README.rdoc → README.md} +12 -2
- data/app/controllers/email_tracker/email_tracker_controller.rb +13 -0
- data/app/models/email_tracker/email.rb +35 -66
- data/app/models/email_tracker/email_open.rb +14 -0
- data/app/models/email_tracker/interceptor.rb +37 -47
- data/app/models/email_tracker/link_click.rb +14 -0
- data/config/initializers/email_tracker.rb +2 -0
- data/config/routes.rb +1 -1
- data/db/migrate/20120610201855_create_email_tracker_emails.rb +3 -3
- data/db/migrate/20120610202021_create_email_tracker_email_opens.rb +15 -0
- data/db/migrate/20120610202122_create_email_tracker_link_clicks.rb +15 -0
- data/lib/email_tracker/engine.rb +5 -0
- data/lib/email_tracker/helpers.rb +24 -0
- data/lib/email_tracker/version.rb +1 -1
- data/lib/email_tracker.rb +10 -0
- metadata +32 -28
- data/app/assets/javascripts/email_tracker/application.js +0 -15
- data/app/assets/stylesheets/email_tracker/application.css +0 -13
- data/app/controllers/email_tracker/application_controller.rb +0 -4
- data/app/controllers/email_tracker/email_instances_controller.rb +0 -31
- data/app/controllers/email_tracker/link_instances_controller.rb +0 -43
- data/app/helpers/email_tracker/application_helper.rb +0 -4
- data/app/models/email_tracker/email_instance.rb +0 -32
- data/app/models/email_tracker/link.rb +0 -10
- data/app/models/email_tracker/link_instance.rb +0 -31
- data/app/views/layouts/email_tracker/application.html.erb +0 -14
- data/db/migrate/20120610202021_create_email_tracker_email_instances.rb +0 -19
- data/db/migrate/20120610202122_create_email_tracker_links.rb +0 -12
- data/db/migrate/20120610202149_create_email_tracker_link_instances.rb +0 -16
data/{README.rdoc → README.md}
RENAMED
@@ -1,8 +1,18 @@
|
|
1
|
-
|
1
|
+
# Email Tracker
|
2
2
|
|
3
3
|
This engine tracks emails in your Ruby on Rails app.
|
4
4
|
|
5
|
-
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
To use in Rails, simply add this to your Gemfile:
|
8
|
+
gem "email_tracker"
|
9
|
+
|
10
|
+
The gem should just start running. All emails will have an embedded tracking image and all links will be tracked.
|
11
|
+
|
12
|
+
## Contributing
|
13
|
+
Please feel free to fork and modify this code.
|
14
|
+
|
15
|
+
## Licence
|
6
16
|
|
7
17
|
Copyright 2012 Jeremy Walker
|
8
18
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module EmailTracker
|
2
|
+
class EmailTrackerController < ActionController::Base
|
3
|
+
|
4
|
+
skip_before_filter :check_logged_in, :only => :opened
|
5
|
+
|
6
|
+
def opened
|
7
|
+
email = Email.find(params[:email_id])
|
8
|
+
email.opens.create!({email_address_hash: params[:email_hash]}, as: :email_tracker_internals)
|
9
|
+
send_data(File.read(File.expand_path("../../../assets/images/email_tracker/transparent.png", __FILE__)))
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -3,83 +3,52 @@ module EmailTracker
|
|
3
3
|
|
4
4
|
belongs_to :owner, polymorphic: true
|
5
5
|
|
6
|
-
has_many :
|
7
|
-
has_many :
|
6
|
+
has_many :opens, class_name: "EmailOpen"
|
7
|
+
has_many :clicks, class_name: "LinkClick"
|
8
8
|
|
9
|
-
attr_accessible :owner, :owner_type, :owner_id, :mailer, :action, as: :email_tracker_internals
|
10
|
-
|
11
|
-
before_create :set_default_name
|
12
|
-
before_create :set_default_description
|
9
|
+
attr_accessible :owner, :owner_type, :owner_id, :mailer, :action, :subject, as: :email_tracker_internals
|
13
10
|
|
14
|
-
def
|
11
|
+
def sent!
|
12
|
+
increment!(:times_sent)
|
13
|
+
end
|
14
|
+
|
15
|
+
def times_opened(since = nil)
|
16
|
+
o = opens.scoped
|
17
|
+
o = o.where("created_at > ?", since) if since
|
18
|
+
o.count
|
19
|
+
end
|
20
|
+
|
21
|
+
def opened_percentage(since = nil)
|
22
|
+
((times_opened(since).to_f / times_sent) * 100).to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def num_links_clicked(since = nil)
|
26
|
+
c = clicks.scoped
|
27
|
+
c = c.where("created_at > ?", since) if since
|
28
|
+
c.count
|
29
|
+
end
|
15
30
|
|
31
|
+
def self.for_email(data)
|
32
|
+
|
33
|
+
if data[:owner]
|
34
|
+
data[:owner_type] = data[:owner].class.name
|
35
|
+
data[:owner_id] = data[:owner].id
|
36
|
+
end
|
37
|
+
|
16
38
|
hash = {
|
17
39
|
mailer: data[:mailer],
|
18
40
|
action: data[:action],
|
41
|
+
subject: data[:subject],
|
19
42
|
owner_type: data[:owner_type],
|
20
43
|
owner_id: data[:owner_id]
|
21
44
|
}
|
22
|
-
|
23
|
-
|
24
|
-
|
45
|
+
|
46
|
+
unless email = self.where(hash).first
|
47
|
+
email = self.new(hash, as: :email_tracker_internals)
|
48
|
+
email.save!
|
25
49
|
end
|
26
50
|
|
27
|
-
email = self.new(hash, as: :email_tracker_internals)
|
28
|
-
email.save!
|
29
51
|
email
|
30
52
|
end
|
31
|
-
|
32
|
-
def create_instance!(email_address, user_id)
|
33
|
-
instances.create!({email_address: email_address, user_id: user_id}, as: :email_tracker_internals)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def set_default_name
|
39
|
-
self.name = if owner
|
40
|
-
if owner.respond_to?(:name)
|
41
|
-
owner.name
|
42
|
-
elsif owner.respond_to?(:title)
|
43
|
-
owner.title
|
44
|
-
else
|
45
|
-
"#{owner.class.name.humanize.capitalize} ##{owner.id}"
|
46
|
-
end
|
47
|
-
else
|
48
|
-
"#{mailer.split("/").last.capitalize} #{action.humanize}"
|
49
|
-
end
|
50
|
-
true
|
51
|
-
end
|
52
|
-
|
53
|
-
def set_default_description
|
54
|
-
self.description = ""
|
55
|
-
true
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
=begin
|
60
|
-
|
61
|
-
|
62
|
-
def times_sent(since = nil)
|
63
|
-
i = instances
|
64
|
-
i = i.where("created_at > ?", since) if since
|
65
|
-
i.count
|
66
53
|
end
|
67
|
-
|
68
|
-
def times_opened(since = nil)
|
69
|
-
i = instances.opened
|
70
|
-
i = i.where("opened_at > ?", since) if since
|
71
|
-
i.count
|
72
|
-
end
|
73
|
-
|
74
|
-
def opened_percentage(since = nil)
|
75
|
-
((times_opened(since).to_f / times_sent(since)) * 100).to_i
|
76
|
-
end
|
77
|
-
|
78
|
-
def num_links_clicked(since = nil)
|
79
|
-
i = link_instances.clicked
|
80
|
-
i = i.where("clicked_at > ?", since) if since
|
81
|
-
i.count
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
=end
|
54
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
module EmailTracker
|
3
|
+
class EmailOpen < ActiveRecord::Base
|
4
|
+
|
5
|
+
attr_accessible :email_id, :email_address_hash, as: :email_tracker_internals
|
6
|
+
|
7
|
+
belongs_to :email
|
8
|
+
belongs_to :user
|
9
|
+
|
10
|
+
def email_address_hash=(hash)
|
11
|
+
self.email_address = EmailTracker.retrieve_email_address_from_hash(hash)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,65 +1,55 @@
|
|
1
1
|
module EmailTracker
|
2
2
|
class Interceptor
|
3
|
-
def self.delivering_email(message)
|
4
3
|
|
4
|
+
def initialize(message)
|
5
|
+
@message = message
|
6
|
+
@hashed_email_address = EmailTracker.hash_email_address(Array(message.to).first)
|
7
|
+
@email = EmailTracker::Email.for_email(message.tracking_data)
|
8
|
+
|
9
|
+
opts = Rails.application.config.action_mailer.default_url_options
|
10
|
+
protocol = opts.fetch(:protocol, "https")
|
11
|
+
host = opts.fetch(:host)
|
12
|
+
@url_base = "#{protocol}://#{host}"
|
13
|
+
|
5
14
|
if message.multipart?
|
6
|
-
message.html_part.body = add_tracking(message
|
15
|
+
message.html_part.body = add_tracking(message.html_part.body)
|
7
16
|
else
|
8
|
-
message.body = add_tracking(message
|
17
|
+
message.body = add_tracking(message.body)
|
9
18
|
end
|
19
|
+
|
20
|
+
@email.sent!
|
10
21
|
end
|
11
22
|
|
12
|
-
def
|
23
|
+
def add_tracking(content)
|
13
24
|
begin
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
tracking_data[:owner_type] = tracking_data[:owner].class.name
|
20
|
-
tracking_data[:owner_id] = tracking_data[:owner].id
|
21
|
-
end
|
22
|
-
|
23
|
-
# Get or create a tracked version of this email
|
24
|
-
tracking_email = EmailTracker::Email.for_email(tracking_data)
|
25
|
+
add_tracking_links(add_tracking_image(content.to_s))
|
26
|
+
rescue
|
27
|
+
p $!
|
28
|
+
end
|
29
|
+
end
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
protocol = opts.fetch(:protocol, "http")
|
32
|
-
host = opts.fetch(:host)
|
33
|
-
url_base = "#{protocol}://#{host}/"
|
31
|
+
def add_tracking_image(content)
|
32
|
+
tracking_url = "#{@url_base}/et/#{@email.id}/#{@hashed_email_address}.gif"
|
33
|
+
tracking_html = "<img src=\"#{tracking_url}\" alt=\"\"/>"
|
34
|
+
content.gsub("</body>", "#{tracking_html}</body>")
|
35
|
+
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
url =
|
43
|
-
if url.starts_with?("mailto")
|
44
|
-
match
|
45
|
-
elsif url.match("et_notrack=true")
|
46
|
-
""
|
47
|
-
else
|
48
|
-
if external = !!url.match("et_external=true")
|
49
|
-
url.gsub!("et_external=true", "")
|
50
|
-
end
|
51
|
-
|
52
|
-
tracked_link = EmailTracker::Link.for_url(url)
|
53
|
-
tracked_link_instance = tracked_link.instances.create!({email_instance: tracking_email_instance, is_externally_viewable: external}, as: :email_tracker_internals)
|
54
|
-
url = "#{url_base}et_click/#{tracked_link_instance.url_code}"
|
55
|
-
"href=\"#{url}\""
|
56
|
-
end
|
37
|
+
def add_tracking_links(content)
|
38
|
+
content.gsub!(/href\=['"]([^"']+)['"]/) do |match|
|
39
|
+
url = $1
|
40
|
+
if url.starts_with?("mailto")
|
41
|
+
match
|
42
|
+
else
|
43
|
+
join_symbol = url.include?("?") ? "&" : "?"
|
44
|
+
url = "href=\"" + (url.starts_with?("http") ? "" : @url_base) + "#{url}?et=#{@email.id}_#{@hashed_email_address}\""
|
57
45
|
end
|
58
|
-
rescue
|
59
|
-
p $!
|
60
46
|
end
|
61
47
|
|
62
48
|
content
|
63
49
|
end
|
50
|
+
|
51
|
+
def self.delivering_email(message)
|
52
|
+
self.new(message)
|
53
|
+
end
|
64
54
|
end
|
65
55
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
'digest/sha1'
|
2
|
+
module EmailTracker
|
3
|
+
class LinkClick < ActiveRecord::Base
|
4
|
+
|
5
|
+
belongs_to :email
|
6
|
+
belongs_to :user
|
7
|
+
|
8
|
+
attr_accessible :email_id, :email_address_hash, :url, as: :email_tracker_internals
|
9
|
+
|
10
|
+
def email_address_hash=(hash)
|
11
|
+
self.email_address = EmailTracker.retrieve_email_address_from_hash(hash)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -26,6 +26,8 @@ class ActionMailer::Base
|
|
26
26
|
# This can be overriden by passing :action as part of tracking_data
|
27
27
|
tracking_data[:action] ||= caller[0][/`([^']*)'/, 1]
|
28
28
|
|
29
|
+
tracking_data[:subject] ||= headers[:subject]
|
30
|
+
|
29
31
|
# Call the original method and add the tracking_data
|
30
32
|
message = mail_without_tracking(headers, &block)
|
31
33
|
message.tracking_data = tracking_data
|
data/config/routes.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
|
-
match "
|
2
|
+
match "et/:email_id/:email_hash" => "email_tracker/email_tracker#opened", as: "email_tracker_opened"
|
3
3
|
match "et_click/:url_code" => "email_tracker/link_instances#clicked", as: "email_tracking_link_clicked"
|
4
4
|
end
|
5
5
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
class CreateEmailTrackerEmails < ActiveRecord::Migration
|
2
2
|
def change
|
3
3
|
create_table :email_tracker_emails do |t|
|
4
|
-
|
5
|
-
t.string :name, null:true
|
6
|
-
t.text :description, null:true
|
7
4
|
|
8
5
|
t.string :mailer, null: false
|
9
6
|
t.string :action, null: false
|
7
|
+
|
8
|
+
t.string :subject, :string, null: false, default: ""
|
9
|
+
t.integer :times_sent, :integer, null: false, default: 0
|
10
10
|
|
11
11
|
t.string :owner_type, null: true
|
12
12
|
t.integer :owner_id, null: true
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateEmailTrackerEmailOpens < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :email_tracker_email_opens do |t|
|
4
|
+
|
5
|
+
t.integer :email_id, null:false
|
6
|
+
t.string :email_address, null:false
|
7
|
+
|
8
|
+
t.integer :user_id, null:true
|
9
|
+
t.datetime :created_at, null:false
|
10
|
+
end
|
11
|
+
|
12
|
+
#add_foreign_key :email_tracker_email_instances, :email_tracker_emails, column: :email_id
|
13
|
+
#add_foreign_key :email_tracker_email_instances, :users, column: :user_id
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateEmailTrackerLinkClicks < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :email_tracker_link_clicks do |t|
|
4
|
+
|
5
|
+
t.integer :email_id, null:false
|
6
|
+
t.string :email_address, null:false
|
7
|
+
t.string :url, null: false
|
8
|
+
|
9
|
+
t.integer :user_id, null:true
|
10
|
+
t.datetime :created_at, null:false
|
11
|
+
|
12
|
+
end
|
13
|
+
#add_foreign_key :email_tracker_email_instances, :email_tracker_emails, column: :email_id
|
14
|
+
end
|
15
|
+
end
|
data/lib/email_tracker/engine.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
module EmailTracker
|
2
|
+
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.before_filter :check_for_email_tracker
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def check_for_email_tracker
|
12
|
+
if params[:et]
|
13
|
+
email_id, email_address_hash = params[:et].split("_")
|
14
|
+
EmailTracker::LinkClick.create({
|
15
|
+
email_id: email_id,
|
16
|
+
email_address_hash: email_address_hash,
|
17
|
+
url: request.fullpath.gsub("et=#{params[:et]}", "")[0...-1]
|
18
|
+
}, as: :email_tracker_internals)
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/email_tracker.rb
CHANGED
@@ -1,4 +1,14 @@
|
|
1
1
|
require "email_tracker/engine"
|
2
|
+
require "email_tracker/helpers"
|
2
3
|
|
3
4
|
module EmailTracker
|
5
|
+
|
6
|
+
def self.hash_email_address(email)
|
7
|
+
Base64.encode64(email).strip[0...-1]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.retrieve_email_address_from_hash(hash)
|
11
|
+
Base64.decode64("#{hash}=")
|
12
|
+
end
|
13
|
+
|
4
14
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: email_tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &70160554639840 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70160554639840
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: sqlite3
|
27
|
-
requirement: &
|
27
|
+
requirement: &70160554639200 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70160554639200
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec-rails
|
38
|
-
requirement: &
|
38
|
+
requirement: &70160554638560 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70160554638560
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: factory_girl_rails
|
49
|
-
requirement: &
|
49
|
+
requirement: &70160554637900 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70160554637900
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: webrat
|
60
|
-
requirement: &
|
60
|
+
requirement: &70160554637240 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,8 +65,19 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
69
|
-
|
68
|
+
version_requirements: *70160554637240
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: method_profiler
|
71
|
+
requirement: &70160554636580 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70160554636580
|
80
|
+
description: A plugin for Rails apps that tracks email.
|
70
81
|
email:
|
71
82
|
- jez.walker@gmail.com
|
72
83
|
executables: []
|
@@ -74,31 +85,24 @@ extensions: []
|
|
74
85
|
extra_rdoc_files: []
|
75
86
|
files:
|
76
87
|
- app/assets/images/email_tracker/transparent.png
|
77
|
-
- app/
|
78
|
-
- app/assets/stylesheets/email_tracker/application.css
|
79
|
-
- app/controllers/email_tracker/application_controller.rb
|
80
|
-
- app/controllers/email_tracker/email_instances_controller.rb
|
81
|
-
- app/controllers/email_tracker/link_instances_controller.rb
|
82
|
-
- app/helpers/email_tracker/application_helper.rb
|
88
|
+
- app/controllers/email_tracker/email_tracker_controller.rb
|
83
89
|
- app/models/email_tracker/email.rb
|
84
|
-
- app/models/email_tracker/
|
90
|
+
- app/models/email_tracker/email_open.rb
|
85
91
|
- app/models/email_tracker/interceptor.rb
|
86
|
-
- app/models/email_tracker/
|
87
|
-
- app/models/email_tracker/link_instance.rb
|
88
|
-
- app/views/layouts/email_tracker/application.html.erb
|
92
|
+
- app/models/email_tracker/link_click.rb
|
89
93
|
- config/initializers/email_tracker.rb
|
90
94
|
- config/routes.rb
|
91
95
|
- db/migrate/20120610201855_create_email_tracker_emails.rb
|
92
|
-
- db/migrate/
|
93
|
-
- db/migrate/
|
94
|
-
- db/migrate/20120610202149_create_email_tracker_link_instances.rb
|
96
|
+
- db/migrate/20120610202021_create_email_tracker_email_opens.rb
|
97
|
+
- db/migrate/20120610202122_create_email_tracker_link_clicks.rb
|
95
98
|
- lib/email_tracker/engine.rb
|
99
|
+
- lib/email_tracker/helpers.rb
|
96
100
|
- lib/email_tracker/version.rb
|
97
101
|
- lib/email_tracker.rb
|
98
102
|
- lib/tasks/email_tracker_tasks.rake
|
99
103
|
- MIT-LICENSE
|
100
104
|
- Rakefile
|
101
|
-
- README.
|
105
|
+
- README.md
|
102
106
|
homepage: http://www.ihid.co.uk/email_tracker
|
103
107
|
licenses: []
|
104
108
|
post_install_message:
|
@@ -122,5 +126,5 @@ rubyforge_project:
|
|
122
126
|
rubygems_version: 1.8.10
|
123
127
|
signing_key:
|
124
128
|
specification_version: 3
|
125
|
-
summary: A plugin for Rails apps that
|
129
|
+
summary: A plugin for Rails apps that tracks email.
|
126
130
|
test_files: []
|
@@ -1,15 +0,0 @@
|
|
1
|
-
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
-
// listed below.
|
3
|
-
//
|
4
|
-
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
-
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
-
//
|
7
|
-
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
-
// the compiled file.
|
9
|
-
//
|
10
|
-
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
-
// GO AFTER THE REQUIRES BELOW.
|
12
|
-
//
|
13
|
-
//= require jquery
|
14
|
-
//= require jquery_ujs
|
15
|
-
//= require_tree .
|
@@ -1,13 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
-
* listed below.
|
4
|
-
*
|
5
|
-
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
-
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
-
*
|
8
|
-
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
-
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
-
*
|
11
|
-
*= require_self
|
12
|
-
*= require_tree .
|
13
|
-
*/
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module EmailTracker
|
2
|
-
class EmailInstancesController < ApplicationController
|
3
|
-
|
4
|
-
skip_before_filter :check_logged_in, :only => :opened
|
5
|
-
|
6
|
-
def opened
|
7
|
-
# Get the instance from the url code
|
8
|
-
@instance = EmailTracker::EmailInstance.where(url_code: params[:url_code]).order("id DESC").first
|
9
|
-
|
10
|
-
# If this hasn't been found, it may be due to a legacy issue
|
11
|
-
# where we used to search by id
|
12
|
-
unless @instance
|
13
|
-
# Search by id
|
14
|
-
@instance = EmailTracker::EmailInstance.find_by_id(params[:url_code])
|
15
|
-
|
16
|
-
# If the instance doesn't exist, or it has a url code (and is therefore post this change) then get out of here
|
17
|
-
unless @instance && @instance.url_code == ""
|
18
|
-
redirect_to root_path
|
19
|
-
return
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# Mark the instance as opened
|
24
|
-
@instance.opened!
|
25
|
-
|
26
|
-
# And send the required image data back
|
27
|
-
send_data(File.read(File.expand_path("../../../assets/images/email_tracker/transparent.png", __FILE__)))
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module EmailTracker
|
2
|
-
class LinkInstancesController < ApplicationController
|
3
|
-
|
4
|
-
skip_before_filter :check_logged_in, :only => :clicked
|
5
|
-
|
6
|
-
def clicked
|
7
|
-
# Get the instance from the url code
|
8
|
-
@instance = EmailTracker::LinkInstance.where(url_code: params[:url_code]).order("id DESC").first
|
9
|
-
|
10
|
-
# If this hasn't been found, it may be due to a legacy issue
|
11
|
-
# where we used to search by id
|
12
|
-
unless @instance
|
13
|
-
# Search by id
|
14
|
-
@instance = EmailTracker::LinkInstance.find_by_id(params[:url_code])
|
15
|
-
|
16
|
-
# If the instance doesn't exist, or it has a url code (and is therefore post this change) then get out of here
|
17
|
-
unless @instance && @instance.url_code == ""
|
18
|
-
redirect_to root_path
|
19
|
-
return
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# We have a valid instance, so mark it as clicked
|
24
|
-
@instance.clicked!
|
25
|
-
redirect_to @instance.link.url
|
26
|
-
|
27
|
-
=begin
|
28
|
-
# If we don't have a user model to care about, just leave
|
29
|
-
return unless Module.const_defined?(:User)
|
30
|
-
|
31
|
-
# Otherwise check whether the user can view this page and act accordingly
|
32
|
-
if @instance.is_externally_viewable? ||
|
33
|
-
!@instance.user ||
|
34
|
-
(responds_to(:user_logged_in?) && user_logged_in?) ||
|
35
|
-
(responds_to(:logged_in?) && logged_in?)
|
36
|
-
else
|
37
|
-
store_user_location(@instance.link.url)
|
38
|
-
@new_user = @instance.user
|
39
|
-
end
|
40
|
-
=end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'digest/sha1'
|
2
|
-
module EmailTracker
|
3
|
-
class EmailInstance < ActiveRecord::Base
|
4
|
-
|
5
|
-
belongs_to :email
|
6
|
-
belongs_to :user
|
7
|
-
has_many :link_instances
|
8
|
-
|
9
|
-
attr_accessible :email_address, :user_id, as: :email_tracker_internals
|
10
|
-
|
11
|
-
scope :opened, where("opened_at IS NOT NULL")
|
12
|
-
|
13
|
-
before_create do
|
14
|
-
if Module.const_defined?(:User)
|
15
|
-
self.user = User.where(email: self.email_address).select(:id).first unless self.user_id
|
16
|
-
end
|
17
|
-
self.url_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
|
18
|
-
true
|
19
|
-
end
|
20
|
-
|
21
|
-
def opened?
|
22
|
-
opened_at != nil ? true : false
|
23
|
-
end
|
24
|
-
|
25
|
-
def opened!
|
26
|
-
unless opened?
|
27
|
-
self.opened_at = DateTime.now
|
28
|
-
save!
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
'digest/sha1'
|
2
|
-
module EmailTracker
|
3
|
-
class LinkInstance < ActiveRecord::Base
|
4
|
-
|
5
|
-
belongs_to :email_instance
|
6
|
-
has_one :email, through: :email_instance
|
7
|
-
has_one :user, through: :email_instance
|
8
|
-
belongs_to :link
|
9
|
-
|
10
|
-
attr_accessible :email_instance, :is_externally_viewable, as: :email_tracker_internals
|
11
|
-
|
12
|
-
scope :clicked, where("clicked_at IS NOT NULL")
|
13
|
-
|
14
|
-
before_create do
|
15
|
-
self.url_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
|
16
|
-
end
|
17
|
-
|
18
|
-
def clicked?
|
19
|
-
clicked_at != nil ? true : false
|
20
|
-
end
|
21
|
-
|
22
|
-
def clicked!
|
23
|
-
unless clicked?
|
24
|
-
self.clicked_at = DateTime.now
|
25
|
-
save!
|
26
|
-
end
|
27
|
-
true
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<title>EmailTracker</title>
|
5
|
-
<%= stylesheet_link_tag "email_tracker/application", :media => "all" %>
|
6
|
-
<%= javascript_include_tag "email_tracker/application" %>
|
7
|
-
<%= csrf_meta_tags %>
|
8
|
-
</head>
|
9
|
-
<body>
|
10
|
-
|
11
|
-
<%= yield %>
|
12
|
-
|
13
|
-
</body>
|
14
|
-
</html>
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class CreateEmailTrackerEmailInstances < ActiveRecord::Migration
|
2
|
-
def change
|
3
|
-
create_table :email_tracker_email_instances do |t|
|
4
|
-
|
5
|
-
t.integer :email_id, null:false
|
6
|
-
|
7
|
-
t.string :email_address, null: false
|
8
|
-
t.string :url_code, null: false
|
9
|
-
t.integer :user_id, null: true
|
10
|
-
|
11
|
-
t.datetime :created_at, null:false
|
12
|
-
t.datetime :updated_at, null:false
|
13
|
-
t.datetime :opened_at, null:true
|
14
|
-
end
|
15
|
-
|
16
|
-
#add_foreign_key :email_tracking_email_instances, :email_tracking_emails, column: :email_id
|
17
|
-
#add_foreign_key :email_tracking_email_instances, :users, column: :user_id
|
18
|
-
end
|
19
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
class CreateEmailTrackerLinks < ActiveRecord::Migration
|
2
|
-
def change
|
3
|
-
create_table :email_tracker_links do |t|
|
4
|
-
t.string :url, null: false
|
5
|
-
|
6
|
-
t.integer :num_clicks, null: false, default: 0
|
7
|
-
|
8
|
-
t.datetime :created_at, null: false
|
9
|
-
t.datetime :updated_at, null: false
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class CreateEmailTrackerLinkInstances < ActiveRecord::Migration
|
2
|
-
def change
|
3
|
-
create_table :email_tracker_link_instances do |t|
|
4
|
-
t.integer :link_id, null: false
|
5
|
-
t.integer :email_instance_id, null: false
|
6
|
-
|
7
|
-
t.string :url_code, null: false
|
8
|
-
t.boolean :is_externally_viewable, null: false, default: false
|
9
|
-
|
10
|
-
t.datetime :clicked_at, null: true
|
11
|
-
end
|
12
|
-
|
13
|
-
#add_foreign_key :email_tracking_link_instances, :email_tracking_links, column: :link_id
|
14
|
-
#add_foreign_key :email_tracking_link_instances, :email_tracking_email_instances, column: :email_instance_id
|
15
|
-
end
|
16
|
-
end
|