mailkick 0.0.2 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 902719cffa741b74a8efa92f326e98c5d359d610
4
- data.tar.gz: 0a15d25bf9ea0201eabc5eeace46cba06b878596
3
+ metadata.gz: c06634c652c84b39afb65d63e54e58a57d212699
4
+ data.tar.gz: 30073ad89e0d42b83844a46822678058ca3b1bf2
5
5
  SHA512:
6
- metadata.gz: b9e635f1f60c3eb5043450aea43133e6a9feb3cccaa1116ca4dfc769c73e1d0f51ecd7dec73d7fc5793f2893e08c4b66f8d774774ac5e2fd8326d890286a9b8b
7
- data.tar.gz: f21ad8fed634b2e4bec5801df0a5d8b305656e4ff4922894461df36700fedb5f2f8704ad00c42e6b11ee2f2b6cd2f85affd3235038e0ff1ef2cd5a9600ceb1c2
6
+ metadata.gz: 018f990ddd1c587e4fcb791fc99b3d6767aeeb8b2eae51aa9e00017432172688bba7bc1adfab45071c540ad626953ccc6216513f4a6e74a7383858b06faebb2f
7
+ data.tar.gz: 62cd53b3f3395af21bf18086cf131d91b8625a4cd71a889792e7f053a96722b337928dbd0160b495d459717003dfdf50760d1484eb821b57cb22b3adb901d08a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.0.3
2
+
3
+ - Added support for multiple lists
4
+ - Changed `mailkick_user` method names - sorry early adopters :(
5
+
1
6
  ## 0.0.2
2
7
 
3
8
  - Added Mailchimp service
data/README.md CHANGED
@@ -62,33 +62,39 @@ class User < ActiveRecord::Base
62
62
  end
63
63
  ```
64
64
 
65
- Get all users who have not unsubscribed
65
+ Get all users who have opted out
66
66
 
67
67
  ```ruby
68
- User.subscribed
68
+ User.opted_out
69
+ ```
70
+
71
+ And those who have not (send to these people)
72
+
73
+ ```ruby
74
+ User.not_opted_out
69
75
  ```
70
76
 
71
77
  Check one user
72
78
 
73
79
  ```ruby
74
- user.subscribed?
80
+ user.opted_out?
75
81
  ```
76
82
 
77
83
  Unsubscribe
78
84
 
79
85
  ```ruby
80
- user.unsubscribe
86
+ user.opt_out
81
87
  ```
82
88
 
83
- Subscribe
89
+ Resubscribe
84
90
 
85
91
  ```ruby
86
- user.subscribe
92
+ user.opt_in
87
93
  ```
88
94
 
89
95
  ## Bounces and Spam Reports
90
96
 
91
- Pull bounces, spam reports, and unsubscribes from your email service.
97
+ Fetch bounces, spam reports, and unsubscribes from your email service.
92
98
 
93
99
  ```ruby
94
100
  Mailkick.fetch_opt_outs
@@ -126,7 +132,7 @@ Will gladly accept pull requests.
126
132
 
127
133
  ### Advanced
128
134
 
129
- For more control over the services, set them by hand.
135
+ For more control over services, set them by hand.
130
136
 
131
137
  ```ruby
132
138
  Mailkick.services = [
@@ -137,7 +143,61 @@ Mailkick.services = [
137
143
 
138
144
  ## Multiple Lists
139
145
 
140
- Coming soon
146
+ You may want to split your emails into multiple categories, like sale emails and order reminders.
147
+
148
+ Set the list in the mailer.
149
+
150
+ ```ruby
151
+ class UserMailer < ActionMailer::Base
152
+
153
+ def order_reminder(user)
154
+ header[:mailkick_list] = "order_reminders"
155
+ # ...
156
+ end
157
+
158
+ end
159
+ ```
160
+
161
+ Pass the `list` option to methods.
162
+
163
+ ```ruby
164
+ # scopes
165
+ User.opted_out(list: "order_reminders")
166
+ User.not_opted_out(list: "order_reminders")
167
+
168
+ # instance methods
169
+ user.opted_out?(list: "order_reminders")
170
+ user.opt_out(list: "order_reminders")
171
+ user.opt_in(list: "order_reminders")
172
+ ```
173
+
174
+ Omitting list (`nil` list) means all lists - including future lists (think “Unsubscribe All”).
175
+
176
+ ```ruby
177
+ # opted out of all lists?
178
+ user.opted_out?
179
+
180
+ # opted out of the order reminder list *or* all lists?
181
+ user.opted_out?(list: "order_reminders")
182
+ ```
183
+
184
+ ### Opt-In Lists
185
+
186
+ For opt-in lists, you’ll need to manage the subscribers yourself.
187
+
188
+ Mailkick stores opt-outs, which you can combine with opt-ins.
189
+
190
+ ```ruby
191
+ # opt-ins minus opt-outs
192
+ User.where(send_me_sales: true).not_opted_out(list: "sales")
193
+ ```
194
+
195
+ Check one user
196
+
197
+ ```ruby
198
+ # opted in and didn't opt out
199
+ user.send_me_sales && !user.opted_out?(list: "sales")
200
+ ```
141
201
 
142
202
  ## Bonus
143
203
 
@@ -6,11 +6,12 @@ module Mailkick
6
6
  end
7
7
 
8
8
  def unsubscribe
9
- if subscribed?
9
+ if !opted_out?
10
10
  Mailkick::OptOut.create! do |o|
11
11
  o.email = @email
12
12
  o.user = @user
13
13
  o.reason = "unsubscribe"
14
+ o.list = @list
14
15
  end
15
16
  end
16
17
 
@@ -22,8 +23,8 @@ module Mailkick
22
23
  opt_out.active = false
23
24
  opt_out.save!
24
25
  end
25
- if @user and @user.respond_to?(:subscribe)
26
- @user.subscribe
26
+ if @user and @user.respond_to?(:opt_in)
27
+ @user.opt_in(@options)
27
28
  end
28
29
 
29
30
  redirect_to subscription_path(params[:id])
@@ -34,24 +35,32 @@ module Mailkick
34
35
  def set_email
35
36
  verifier = ActiveSupport::MessageVerifier.new(Mailkick.secret_token)
36
37
  begin
37
- @email, user_id, user_type = verifier.verify(params[:id])
38
+ @email, user_id, user_type, @list = verifier.verify(params[:id])
38
39
  if user_type
39
40
  # on the unprobabilistic chance user_type is compromised, not much damage
40
41
  @user = user_type.constantize.find(user_id)
41
42
  end
43
+ @options = {}
44
+ @options[:list] = @list if @list
42
45
  rescue ActiveSupport::MessageVerifier::InvalidSignature
43
46
  render text: "Subscription not found", status: :bad_request
44
47
  end
45
48
  end
46
49
 
47
- def subscribed?
48
- if @user and @user.respond_to?(:subscribed?)
49
- @user.subscribed?
50
+ def opted_out?(options = {})
51
+ options = @options.merge(options)
52
+ if @user and @user.respond_to?(:opted_out?)
53
+ @user.opted_out?(options)
50
54
  else
51
- Mailkick::OptOut.where(email: @email, active: true).empty?
55
+ relation = Mailkick::OptOut.where(email: @email, active: true)
56
+ if options[:list]
57
+ relation.where("list IS NULL OR list = ?", options[:list])
58
+ else
59
+ relation.where("list IS NULL")
60
+ end.any?
52
61
  end
53
62
  end
54
- helper_method :subscribed?
63
+ helper_method :opted_out?
55
64
 
56
65
  def subscribe_url(options = {})
57
66
  subscribe_subscription_path(params[:id], options)
@@ -24,12 +24,12 @@
24
24
  </head>
25
25
  <body>
26
26
  <div class="container">
27
- <% if subscribed? %>
28
- <p>You are subscribed.</p>
29
- <p><%= link_to "Unsubscribe", unsubscribe_url %></p>
30
- <% else %>
27
+ <% if opted_out? %>
31
28
  <p>You are unsubscribed.</p>
32
29
  <p><%= link_to "Resubscribe", subscribe_url %></p>
30
+ <% else %>
31
+ <p>You are subscribed.</p>
32
+ <p><%= link_to "Unsubscribe", unsubscribe_url %></p>
33
33
  <% end %>
34
34
  </div>
35
35
  </body>
@@ -6,6 +6,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
6
6
  t.string :user_type
7
7
  t.boolean :active, null: false, default: true
8
8
  t.string :reason
9
+ t.string :list
9
10
  t.timestamps
10
11
  end
11
12
 
@@ -3,36 +3,54 @@ module Mailkick
3
3
 
4
4
  def mailkick_user(options = {})
5
5
  class_eval do
6
- scope :subscribed, proc{ joins(sanitize_sql_array(["LEFT JOIN mailkick_opt_outs ON #{table_name}.email = mailkick_opt_outs.email OR (#{table_name}.id = mailkick_opt_outs.user_id AND mailkick_opt_outs.user_type = ?)", name])).where("active != ?", true).uniq }
7
-
8
- def opt_outs
9
- Mailkick::OptOut.where("email = ? OR (user_id = ? AND user_type = ?)", email, id, self.class.name)
10
- end
6
+ scope :opted_out, proc {|options = {}|
7
+ binds = [self.class.name, true]
8
+ if options[:list]
9
+ query = "(list IS NULL OR list = ?)"
10
+ binds << options[:list]
11
+ else
12
+ query = "list IS NULL"
13
+ end
14
+ where("#{options[:not] ? "NOT " : ""}EXISTS(SELECT * FROM mailkick_opt_outs WHERE (#{table_name}.email = mailkick_opt_outs.email OR (#{table_name}.id = mailkick_opt_outs.user_id AND mailkick_opt_outs.user_type = ?)) AND active = ? AND #{query})", *binds)
15
+ }
16
+ scope :not_opted_out, proc {|options = {}|
17
+ opted_out(options.merge(not: true))
18
+ }
11
19
 
12
- def subscribed?
13
- opt_outs.where(active: true).empty?
20
+ def opt_outs(options = {})
21
+ relation = Mailkick::OptOut.where("email = ? OR (user_id = ? AND user_type = ?)", email, id, self.class.name)
22
+ if options[:list]
23
+ relation.where("list IS NULL OR list = ?", options[:list])
24
+ else
25
+ relation.where(list: nil)
26
+ end
14
27
  end
15
28
 
16
- def subscribe
17
- opt_outs.where(active: true).each do |opt_out|
18
- opt_out.active = false
19
- opt_out.save!
20
- end
21
- true
29
+ def opted_out?(options = {})
30
+ opt_outs(options).where(active: true).any?
22
31
  end
23
32
 
24
- def unsubscribe
25
- if subscribed?
33
+ def opt_out(options = {})
34
+ if !opted_out?(options)
26
35
  OptOut.create! do |o|
27
36
  o.email = email
28
37
  o.user = self
29
38
  o.reason = "unsubscribe"
39
+ o.list = options[:list]
30
40
  o.save!
31
41
  end
32
42
  end
33
43
  true
34
44
  end
35
45
 
46
+ def opt_in(options = {})
47
+ opt_outs(options).where(active: true).each do |opt_out|
48
+ opt_out.active = false
49
+ opt_out.save!
50
+ end
51
+ true
52
+ end
53
+
36
54
  end
37
55
  end
38
56
 
@@ -9,9 +9,14 @@ module Mailkick
9
9
  def process
10
10
  email = message.to.first
11
11
  user = Mailkick.user_method.call(email) if Mailkick.user_method
12
+ list = message[:mailkick_list].try(:value)
13
+ if list
14
+ # remove header
15
+ message[:mailkick_list] = nil
16
+ end
12
17
 
13
18
  verifier = ActiveSupport::MessageVerifier.new(Mailkick.secret_token)
14
- token = verifier.generate([email, user.try(:id), user.try(:class).try(:name)])
19
+ token = verifier.generate([email, user.try(:id), user.try(:class).try(:name), list])
15
20
 
16
21
  parts = message.parts.any? ? message.parts : [message]
17
22
  parts.each do |part|
@@ -1,3 +1,3 @@
1
1
  module Mailkick
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-04 00:00:00.000000000 Z
11
+ date: 2014-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler