ahoy_email 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +19 -3
- data/app/controllers/ahoy/messages_controller.rb +4 -8
- data/app/models/ahoy/message.rb +1 -1
- data/lib/ahoy_email/engine.rb +3 -1
- data/lib/ahoy_email/processor.rb +10 -7
- data/lib/ahoy_email/version.rb +1 -1
- data/lib/generators/ahoy_email/install_generator.rb +3 -20
- metadata +7 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c056fb39ad0a8774c23582f8a37fbea9f460d903f4f05565e31b5670b0ce615d
|
4
|
+
data.tar.gz: 5b489942efd5cb224f068d06d06fdd9e9e68f65d256ded15be359ccdfc4190ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55a1a58246738297be5e07198ef58014a13596fa372cf8127a4b4670ddfb7465c09371250ff269306cfc03ef7704ec28bc716669857eb6bc40fbe3132c94564a
|
7
|
+
data.tar.gz: b58a064519fb0ef57a255db8a57c4b0101f0fbf029e3110f1ece205e927bb13a8e4c3d5f95888e36be41f25eed6f0dc73ee995ff546d27771604c6b4058fd392
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -53,7 +53,7 @@ AhoyEmail.default_options[:message] = false
|
|
53
53
|
|
54
54
|
Ahoy records the user a message is sent to - not just the email address. This gives you a full history of messages for each user, even if he or she changes addresses.
|
55
55
|
|
56
|
-
By default, Ahoy tries `@user` then `params[:user]` then `User.find_by(email: message.to
|
56
|
+
By default, Ahoy tries `@user` then `params[:user]` then `User.find_by(email: message.to)` to find the user.
|
57
57
|
|
58
58
|
You can pass a specific user with:
|
59
59
|
|
@@ -243,6 +243,22 @@ end
|
|
243
243
|
AhoyEmail.subscribers << EmailSubscriber.new
|
244
244
|
```
|
245
245
|
|
246
|
+
## Data Protection
|
247
|
+
|
248
|
+
Protect the privacy of your users by encrypting the `to` field. [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted) is great for this. Use [blind_index](https://github.com/ankane/blind_index) if you need to query by the `to` field.
|
249
|
+
|
250
|
+
Create `app/models/ahoy/message.rb` with:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
class Ahoy::Message < ApplicationRecord
|
254
|
+
self.table_name = "ahoy_messages"
|
255
|
+
belongs_to :user, polymorphic: true, optional: true
|
256
|
+
|
257
|
+
attr_encrypted :to, key: ...
|
258
|
+
blind_index :to, key: ...
|
259
|
+
end
|
260
|
+
```
|
261
|
+
|
246
262
|
## Reference
|
247
263
|
|
248
264
|
Set global options
|
@@ -303,10 +319,10 @@ Breaking changes
|
|
303
319
|
|
304
320
|
```ruby
|
305
321
|
# old
|
306
|
-
user: ->(mailer, message) { User.find_by(email: message.to
|
322
|
+
user: ->(mailer, message) { User.find_by(email: message.to) }
|
307
323
|
|
308
324
|
# new
|
309
|
-
user: -> { User.find_by(email: message.to
|
325
|
+
user: -> { User.find_by(email: message.to) }
|
310
326
|
```
|
311
327
|
|
312
328
|
- Invalid options now throw an `ArgumentError`
|
@@ -1,13 +1,9 @@
|
|
1
1
|
module Ahoy
|
2
2
|
class MessagesController < ApplicationController
|
3
3
|
filters = _process_action_callbacks.map(&:filter) - AhoyEmail.preserve_callbacks
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
skip_around_action(*filters, raise: false)
|
8
|
-
else
|
9
|
-
skip_action_callback *filters
|
10
|
-
end
|
4
|
+
skip_before_action(*filters, raise: false)
|
5
|
+
skip_after_action(*filters, raise: false)
|
6
|
+
skip_around_action(*filters, raise: false)
|
11
7
|
|
12
8
|
before_action :set_message
|
13
9
|
|
@@ -25,7 +21,7 @@ module Ahoy
|
|
25
21
|
def click
|
26
22
|
if @message && !@message.clicked_at
|
27
23
|
@message.clicked_at = Time.now
|
28
|
-
@message.opened_at ||= @message.clicked_at
|
24
|
+
@message.opened_at ||= @message.clicked_at if @message.respond_to?(:opened_at=)
|
29
25
|
@message.save!
|
30
26
|
end
|
31
27
|
|
data/app/models/ahoy/message.rb
CHANGED
data/lib/ahoy_email/engine.rb
CHANGED
@@ -13,7 +13,9 @@ module AhoyEmail
|
|
13
13
|
app.config
|
14
14
|
end
|
15
15
|
|
16
|
-
creds.respond_to?(:secret_key_base) ? creds.secret_key_base : creds.secret_token
|
16
|
+
token = creds.respond_to?(:secret_key_base) ? creds.secret_key_base : creds.secret_token
|
17
|
+
token ||= app.secret_key_base # should come first, but need to maintain backward compatibility
|
18
|
+
token
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/lib/ahoy_email/processor.rb
CHANGED
@@ -58,7 +58,9 @@ module AhoyEmail
|
|
58
58
|
|
59
59
|
def track_open
|
60
60
|
if html_part?
|
61
|
-
|
61
|
+
part = message.html_part || message
|
62
|
+
raw_source = part.body.raw_source
|
63
|
+
|
62
64
|
regex = /<\/body>/i
|
63
65
|
url =
|
64
66
|
url_for(
|
@@ -71,18 +73,18 @@ module AhoyEmail
|
|
71
73
|
|
72
74
|
# try to add before body tag
|
73
75
|
if raw_source.match(regex)
|
74
|
-
raw_source.gsub
|
76
|
+
part.body = raw_source.gsub(regex, "#{pixel}\\0")
|
75
77
|
else
|
76
|
-
raw_source
|
78
|
+
part.body = raw_source + pixel
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
83
|
def track_links
|
82
84
|
if html_part?
|
83
|
-
|
85
|
+
part = message.html_part || message
|
84
86
|
|
85
|
-
doc = Nokogiri::HTML(body.raw_source)
|
87
|
+
doc = Nokogiri::HTML(part.body.raw_source)
|
86
88
|
doc.css("a[href]").each do |link|
|
87
89
|
uri = parse_uri(link["href"])
|
88
90
|
next unless trackable?(uri)
|
@@ -98,6 +100,8 @@ module AhoyEmail
|
|
98
100
|
end
|
99
101
|
|
100
102
|
if options[:click] && !skip_attribute?(link, "click")
|
103
|
+
raise "Secret token is empty" unless AhoyEmail.secret_token
|
104
|
+
|
101
105
|
# TODO sign more than just url and transition to HMAC-SHA256
|
102
106
|
signature = OpenSSL::HMAC.hexdigest("SHA1", AhoyEmail.secret_token, link["href"])
|
103
107
|
link["href"] =
|
@@ -111,8 +115,7 @@ module AhoyEmail
|
|
111
115
|
end
|
112
116
|
end
|
113
117
|
|
114
|
-
|
115
|
-
body.raw_source.sub!(body.raw_source, doc.to_s)
|
118
|
+
part.body = doc.to_s
|
116
119
|
end
|
117
120
|
end
|
118
121
|
|
data/lib/ahoy_email/version.rb
CHANGED
@@ -1,34 +1,17 @@
|
|
1
|
-
# taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
|
2
|
-
require "rails/generators"
|
3
|
-
require "rails/generators/migration"
|
4
|
-
require "active_record"
|
5
1
|
require "rails/generators/active_record"
|
6
2
|
|
7
3
|
module AhoyEmail
|
8
4
|
module Generators
|
9
5
|
class InstallGenerator < Rails::Generators::Base
|
10
|
-
include
|
11
|
-
|
12
|
-
source_root File.expand_path("../templates", __FILE__)
|
13
|
-
|
14
|
-
# Implement the required interface for Rails::Generators::Migration.
|
15
|
-
def self.next_migration_number(dirname) #:nodoc:
|
16
|
-
next_migration_number = current_migration_number(dirname) + 1
|
17
|
-
if ActiveRecord::Base.timestamped_migrations
|
18
|
-
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
|
19
|
-
else
|
20
|
-
"%.3d" % next_migration_number
|
21
|
-
end
|
22
|
-
end
|
6
|
+
include ActiveRecord::Generators::Migration
|
7
|
+
source_root File.join(__dir__, "templates")
|
23
8
|
|
24
9
|
def copy_migration
|
25
10
|
migration_template "install.rb", "db/migrate/create_ahoy_messages.rb", migration_version: migration_version
|
26
11
|
end
|
27
12
|
|
28
13
|
def migration_version
|
29
|
-
|
30
|
-
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
31
|
-
end
|
14
|
+
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
32
15
|
end
|
33
16
|
end
|
34
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ahoy_email
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionmailer
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: addressable
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,7 +137,7 @@ dependencies:
|
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: sqlite3
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - ">="
|
@@ -150,20 +150,6 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: sqlite3
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: 1.3.0
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: 1.3.0
|
167
153
|
description:
|
168
154
|
email: andrew@chartkick.com
|
169
155
|
executables: []
|
@@ -198,15 +184,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
184
|
requirements:
|
199
185
|
- - ">="
|
200
186
|
- !ruby/object:Gem::Version
|
201
|
-
version: '2.
|
187
|
+
version: '2.4'
|
202
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
189
|
requirements:
|
204
190
|
- - ">="
|
205
191
|
- !ruby/object:Gem::Version
|
206
192
|
version: '0'
|
207
193
|
requirements: []
|
208
|
-
|
209
|
-
rubygems_version: 2.7.6
|
194
|
+
rubygems_version: 3.0.4
|
210
195
|
signing_key:
|
211
196
|
specification_version: 4
|
212
197
|
summary: Email analytics for Rails
|