mail_manager 3.0.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/.ruby-version +1 -1
  5. data/Gemfile +27 -10
  6. data/LICENSE.txt +2 -2
  7. data/MIT-LICENSE +1 -1
  8. data/README.md +97 -15
  9. data/{features/bounce_management.feature → app/assets/images/mail_manager/.gitkeep} +0 -0
  10. data/app/assets/images/mail_manager/BottomRight.gif +0 -0
  11. data/app/assets/images/mail_manager/MidRight.gif +0 -0
  12. data/app/assets/images/mail_manager/TopCenter.gif +0 -0
  13. data/app/assets/images/mail_manager/TopRight.gif +0 -0
  14. data/app/assets/images/mail_manager/calendar_date_select/calendar.gif +0 -0
  15. data/app/assets/images/mail_manager/iReach_logo.gif +0 -0
  16. data/app/assets/images/mail_manager/spacer.gif +0 -0
  17. data/app/assets/images/mail_manager/topMid.gif +0 -0
  18. data/app/assets/javascripts/mail_manager/application.js +19 -1
  19. data/app/assets/javascripts/mail_manager/jquery-ui-timepicker-addon.js +2134 -0
  20. data/app/assets/stylesheets/mail_manager/admin.css +261 -0
  21. data/app/assets/stylesheets/mail_manager/application.css +3 -1
  22. data/app/assets/stylesheets/mail_manager/nav.css +68 -0
  23. data/app/assets/stylesheets/mail_manager/timepicker.css +11 -0
  24. data/app/controllers/mail_manager/application_controller.rb +7 -2
  25. data/app/controllers/mail_manager/bounces_controller.rb +5 -10
  26. data/app/controllers/mail_manager/contacts_controller.rb +42 -20
  27. data/app/controllers/mail_manager/mailing_lists_controller.rb +5 -12
  28. data/app/controllers/mail_manager/mailings_controller.rb +18 -18
  29. data/app/controllers/mail_manager/messages_controller.rb +3 -10
  30. data/app/controllers/mail_manager/subscriptions_controller.rb +16 -75
  31. data/app/helpers/mail_manager/layout_helper.rb +43 -0
  32. data/app/models/mail_manager/bounce.rb +16 -5
  33. data/app/models/mail_manager/contact.rb +64 -1
  34. data/app/models/mail_manager/mailable.rb +14 -0
  35. data/app/models/mail_manager/mailer.rb +48 -81
  36. data/app/models/mail_manager/mailing.rb +23 -42
  37. data/app/models/mail_manager/message.rb +52 -8
  38. data/app/models/mail_manager/subscription.rb +9 -3
  39. data/app/models/status_history.rb +3 -2
  40. data/app/views/layouts/mail_manager/application.html.erb +33 -5
  41. data/app/views/layouts/mail_manager/layout.html.erb +15 -0
  42. data/app/views/mail_manager/bounces/index.html.erb +6 -4
  43. data/app/views/mail_manager/bounces/show.html.erb +3 -3
  44. data/app/views/mail_manager/contacts/_form.html.erb +7 -23
  45. data/app/views/mail_manager/contacts/edit.html.erb +3 -3
  46. data/app/views/mail_manager/contacts/index.html.erb +14 -28
  47. data/app/views/mail_manager/contacts/new.html.erb +2 -2
  48. data/app/views/mail_manager/contacts/show.html.erb +5 -5
  49. data/app/views/mail_manager/contacts/subscribe.html.erb +1 -1
  50. data/app/views/mail_manager/mailer/double_opt_in.erb +1 -1
  51. data/app/views/mail_manager/mailer/double_opt_in.html.erb +6 -0
  52. data/app/views/mail_manager/mailer/unsubscribed.erb +1 -1
  53. data/app/views/mail_manager/mailer/unsubscribed.html.erb +1 -1
  54. data/app/views/mail_manager/mailing_lists/_form.html.erb +8 -17
  55. data/app/views/mail_manager/mailing_lists/edit.html.erb +4 -4
  56. data/app/views/mail_manager/mailing_lists/index.html.erb +6 -5
  57. data/app/views/mail_manager/mailing_lists/new.html.erb +3 -3
  58. data/app/views/mail_manager/mailings/_form.html.erb +22 -44
  59. data/app/views/mail_manager/mailings/edit.html.erb +3 -3
  60. data/app/views/mail_manager/mailings/index.html.erb +23 -27
  61. data/app/views/mail_manager/mailings/new.html.erb +2 -2
  62. data/app/views/mail_manager/mailings/test.html.erb +3 -3
  63. data/app/views/mail_manager/messages/index.html.erb +2 -2
  64. data/app/views/mail_manager/subscriptions/_form.html.erb +1 -1
  65. data/app/views/mail_manager/subscriptions/_subscriptions.html.erb +2 -2
  66. data/app/views/mail_manager/subscriptions/edit.html.erb +2 -2
  67. data/app/views/mail_manager/subscriptions/index.html.erb +3 -3
  68. data/app/views/mail_manager/subscriptions/new.html.erb +1 -1
  69. data/app/views/mail_manager/subscriptions/unsubscribe.html.erb +1 -1
  70. data/app/views/mail_manager/subscriptions/unsubscribe_by_email_address.html.erb +3 -3
  71. data/config/locales/en.yml +13 -0
  72. data/config/locales/mailings.en.yml +52 -0
  73. data/config/routes.rb +21 -19
  74. data/db/migrate/008_add_bounces_count_to_mailings.rb +14 -0
  75. data/db/migrate/009_add_messages_count_to_mailings.rb +14 -0
  76. data/db/migrate/010_add_login_token_to_contact.rb +11 -0
  77. data/db/migrate/011_add_deleted_at_to_mailing.rb +11 -0
  78. data/lib/delayed/mailer.rb +9 -5
  79. data/lib/delayed/status.rb +6 -2
  80. data/lib/delayed_overrides/worker.rb +21 -0
  81. data/lib/deleteable.rb +13 -14
  82. data/lib/mail_manager/config.rb +3 -3
  83. data/lib/mail_manager/engine.rb +136 -7
  84. data/lib/mail_manager/lock.rb +1 -0
  85. data/lib/mail_manager/version.rb +1 -1
  86. data/lib/tasks/mail_manager.rake +92 -56
  87. data/mail_manager.gemspec +4 -0
  88. data/spec/rails_helper.rb +50 -0
  89. data/spec/spec_helper.rb +87 -48
  90. data/spec/test_app/.env.development +3 -0
  91. data/spec/test_app/.env.test +2 -0
  92. data/spec/test_app/.rspec +1 -0
  93. data/spec/test_app/Procfile +3 -0
  94. data/spec/test_app/app/controllers/application_controller.rb +4 -0
  95. data/spec/test_app/app/models/ability.rb +7 -0
  96. data/spec/test_app/app/models/user.rb +8 -2
  97. data/spec/test_app/app/models/user_with_role.rb +22 -0
  98. data/spec/test_app/config/database.postgres.yml +21 -0
  99. data/spec/test_app/config/database.sqlite.yml +2 -2
  100. data/spec/test_app/config/environment.rb +2 -2
  101. data/spec/test_app/config/environments/test.rb +13 -0
  102. data/spec/test_app/config/mail_manager.yml +66 -2
  103. data/spec/test_app/config/routes.rb +0 -1
  104. data/spec/test_app/db/migrate/20150420163235_add_bounces_count_to_mailings.rb +14 -0
  105. data/spec/test_app/db/migrate/20150420163804_add_messages_count_to_mailings.rb +14 -0
  106. data/spec/test_app/db/migrate/20150421151457_add_login_token_to_contact.rb +11 -0
  107. data/spec/test_app/db/migrate/20150423143754_add_deleted_at_to_mailing.rb +11 -0
  108. data/spec/test_app/db/schema.rb +10 -5
  109. data/spec/test_app/db/structure.sql +150 -15
  110. data/spec/test_app/features/bounce_management.feature +11 -0
  111. data/spec/test_app/features/contact_management.feature +91 -0
  112. data/{features → spec/test_app/features}/mailable.feature +3 -1
  113. data/spec/test_app/features/mailing_list_management.feature +39 -0
  114. data/spec/test_app/features/mailing_management.feature +60 -0
  115. data/{features → spec/test_app/features}/message.feature +4 -4
  116. data/spec/test_app/features/message_management.feature +22 -0
  117. data/spec/test_app/features/step_definitions/bounce_steps.rb +4 -0
  118. data/spec/test_app/features/step_definitions/contact_steps.rb +63 -0
  119. data/spec/test_app/features/step_definitions/debugging_steps.rb +3 -0
  120. data/spec/test_app/features/step_definitions/email_steps.rb +6 -0
  121. data/spec/test_app/features/step_definitions/job_steps.rb +25 -0
  122. data/spec/test_app/features/step_definitions/login_steps.rb +4 -0
  123. data/spec/test_app/features/step_definitions/mailing_list.rb +17 -0
  124. data/spec/test_app/features/step_definitions/mailing_steps.rb +51 -0
  125. data/spec/test_app/features/step_definitions/subscription_steps.rb +26 -0
  126. data/{features → spec/test_app/features}/step_definitions/webrat_steps.rb +10 -6
  127. data/spec/test_app/features/subscription_management.feature +62 -0
  128. data/spec/test_app/features/support/env.rb +37 -0
  129. data/spec/test_app/features/support/paths.rb +36 -0
  130. data/spec/test_app/lib/debugging.rb +61 -0
  131. data/spec/test_app/lib/post_office_manager.rb +71 -0
  132. data/spec/test_app/public/subscribe.html +40 -0
  133. data/spec/test_app/script/full_suite +50 -0
  134. data/spec/test_app/script/post_office +25 -0
  135. data/spec/test_app/script/rails +20 -0
  136. data/spec/test_app/script/rspec_multi_db +34 -0
  137. data/spec/test_app/spec/controllers/mail_manager/bounces_controller_spec.rb +59 -0
  138. data/spec/test_app/spec/controllers/mail_manager/contacts_controller_spec.rb +178 -0
  139. data/spec/test_app/spec/controllers/mail_manager/mailing_lists_controller_spec.rb +164 -0
  140. data/spec/test_app/spec/controllers/mail_manager/mailings_controller_spec.rb +184 -0
  141. data/spec/test_app/spec/controllers/users_controller_spec.rb +47 -46
  142. data/spec/test_app/spec/factories/_functions.rb +27 -0
  143. data/spec/test_app/spec/factories/contacts.rb +7 -0
  144. data/spec/test_app/spec/factories/mail_manager_bounces.rb +13 -0
  145. data/spec/test_app/spec/factories/mailable.rb +8 -0
  146. data/spec/test_app/spec/factories/mailings.rb +7 -1
  147. data/spec/test_app/spec/factories/message.rb +7 -0
  148. data/spec/test_app/spec/factories/users.rb +19 -7
  149. data/spec/test_app/spec/features/mail_manager/bounce_spec.rb +73 -0
  150. data/spec/test_app/spec/features/mail_manager/double_opt_in_spec.rb +62 -0
  151. data/spec/test_app/spec/features/mail_manager/mailing_spec.rb +46 -0
  152. data/spec/test_app/spec/features/navigation_spec.rb +9 -0
  153. data/spec/test_app/spec/helpers/mail_manager/layout_helper_spec.rb +41 -0
  154. data/spec/test_app/spec/helpers/mail_manager/subscriptions_helper_spec.rb +14 -0
  155. data/spec/test_app/spec/models/delayed/mailer_spec.rb +27 -0
  156. data/spec/test_app/spec/models/delayed/status_job_spec.rb +13 -0
  157. data/spec/test_app/spec/models/delayed/status_spec.rb +37 -0
  158. data/spec/test_app/spec/models/mail_manager/bounce_spec.rb +23 -3
  159. data/spec/test_app/spec/models/mail_manager/engine_spec.rb +79 -0
  160. data/spec/test_app/spec/models/mail_manager/mailable_spec.rb +10 -0
  161. data/spec/test_app/spec/models/mail_manager/mailer_spec.rb +35 -3
  162. data/spec/test_app/spec/models/mail_manager/mailing_list_spec.rb +5 -5
  163. data/spec/test_app/spec/models/mail_manager/mailing_spec.rb +58 -0
  164. data/spec/test_app/spec/models/mail_manager/message_spec.rb +112 -0
  165. data/spec/test_app/spec/models/user_spec.rb +10 -8
  166. data/spec/test_app/spec/rails_helper.rb +86 -0
  167. data/spec/test_app/spec/requests/users_spec.rb +3 -3
  168. data/spec/test_app/spec/routing/mail_manager/bounces_routing_spec.rb +27 -0
  169. data/spec/test_app/spec/routing/mail_manager/contacts_routing_spec.rb +36 -0
  170. data/spec/test_app/spec/routing/mail_manager/mailing_lists_routing_spec.rb +36 -0
  171. data/spec/test_app/spec/routing/mail_manager/mailings_routing_spec.rb +36 -0
  172. data/spec/test_app/spec/spec_helper.rb +82 -32
  173. data/spec/test_app/spec/support/continuance.rb +18 -0
  174. data/spec/test_app/spec/support/custom_matchers.rb +17 -0
  175. data/spec/test_app/spec/support/database_cleaner.rb +10 -1
  176. data/spec/test_app/spec/views/mail_manager/bounces/index.html.erb_spec.rb +32 -0
  177. data/spec/test_app/spec/views/mail_manager/bounces/show.html.erb_spec.rb +12 -0
  178. data/spec/test_app/spec/views/users/edit.html.erb_spec.rb +8 -5
  179. data/spec/test_app/spec/views/users/index.html.erb_spec.rb +10 -19
  180. data/spec/test_app/spec/views/users/new.html.erb_spec.rb +9 -6
  181. data/spec/test_app/spec/views/users/show.html.erb_spec.rb +8 -9
  182. metadata +231 -75
  183. data/.DS_Store +0 -0
  184. data/README.rdoc +0 -3
  185. data/app/.DS_Store +0 -0
  186. data/app/controllers/mail_manager/base_controller.rb +0 -22
  187. data/app/models/.DS_Store +0 -0
  188. data/features/contact_management.feature +0 -24
  189. data/features/mailing_management.feature +0 -78
  190. data/features/step_definitions/email_steps.rb +0 -50
  191. data/features/step_definitions/mlm_steps.rb +0 -11
  192. data/features/step_definitions/pickle_steps.rb +0 -41
  193. data/features/subscription_management.feature +0 -17
  194. data/features/support/env.rb +0 -11
  195. data/features/support/paths.rb +0 -44
  196. data/lib/tasks/mail_manager_tasks.rake +0 -4
  197. data/lib/tasks/rspec.rake +0 -165
  198. data/spec/test_app/bin/cucumber +0 -7
  199. data/spec/test_app/bin/rails +0 -10
  200. data/spec/test_app/bin/rake +0 -7
  201. data/spec/test_app/bin/rspec +0 -7
  202. data/spec/test_app/bin/spring +0 -18
  203. data/spec/test_app/spec/routing/users_routing_spec.rb +0 -35
  204. data/spec/test_app/spec/support/post_office.rb +0 -13
@@ -26,25 +26,18 @@ module MailManager
26
26
 
27
27
  accepts_nested_attributes_for :mailable
28
28
 
29
+ include Deleteable if (column_names.include?('deleted_at') rescue false)
30
+
29
31
  attr_accessor :bounce_count
30
32
 
31
33
  validates_presence_of :subject
32
34
  #validates_presence_of :mailable
33
35
 
34
- scope :ready, lambda {{:conditions => ["(status='scheduled' AND scheduled_at < ?) OR status='resumed'",Time.now.utc]}}
36
+ scope :ready, lambda {{:conditions => ["(status='scheduled' AND scheduled_at < ?)",Time.now.utc]}}
35
37
  scope :by_statuses, lambda {|*statuses| {:conditions => ["status in (#{statuses.collect{|bindings,status| '?'}.join(",")})",statuses].flatten}}
36
38
 
37
- def self.with_bounces(bounce_status=nil)
38
- bounce_status_condition = bounce_status.present? ? ActiveRecord::Base.send(:sanitize_sql_array,[" WHERE status=?", bounce_status]) : ''
39
- bounce_query = "SELECT mailing_id, COUNT(id) AS count from #{MailManager.table_prefix}bounces #{bounce_status_condition} group by mailing_id"
40
- bounce_data = Bounce.connection.execute(bounce_query).inject({}){|hash,(mailing_id,count)| hash.merge(mailing_id => count)}
41
- mailings = scoped
42
- mailings = mailings.where("id in (#{bounce_data.keys.select(&:present?).join(',')})") if bounce_data.keys.select(&:present?).present?
43
- mailings.order("created_at desc").map{|mailing| mailing.bounce_count = bounce_data[mailing.id]; mailing}
44
- end
45
-
46
39
  include StatusHistory
47
- override_statuses(['pending','scheduled','processing','paused','resumed','cancelled','completed'],'pending')
40
+ override_statuses(['pending','scheduled','processing','cancelled','completed'],'pending')
48
41
  before_create :set_default_status
49
42
 
50
43
  attr_protected :id
@@ -78,9 +71,7 @@ module MailManager
78
71
  begin
79
72
  # use the cached mailing parts, set messages mailing to self
80
73
  message.mailing=self
81
- message.change_status(:processing)
82
74
  message.deliver
83
- message.change_status(:sent)
84
75
  rescue => e
85
76
  message.result = "Error: #{e.message} - #{e.backtrace.join("\n")}"
86
77
  message.change_status(:failed)
@@ -212,24 +203,16 @@ module MailManager
212
203
  self.mailing_lists = mailing_list_ids.collect{|mailing_list_id| MailingList.find_by_id(mailing_list_id)}
213
204
  end
214
205
 
215
- def can_pause?
216
- ['processing'].include?(status.to_s)
217
- end
218
-
219
206
  def can_edit?
220
- ['pending','scheduled','paused'].include?(status.to_s)
207
+ ['pending','scheduled'].include?(status.to_s)
221
208
  end
222
209
 
223
210
  def can_cancel?
224
- ['pending','scheduled','processing','paused','resumed'].include?(status.to_s)
225
- end
226
-
227
- def can_resume?
228
- ['paused'].include?(status.to_s)
211
+ ['pending','scheduled','processing'].include?(status.to_s)
229
212
  end
230
213
 
231
214
  def can_schedule?
232
- ['pending'].include?(status.to_s)
215
+ ['pending'].include?(status.to_s) && scheduled_at.present?
233
216
  end
234
217
 
235
218
  def schedule
@@ -237,30 +220,28 @@ module MailManager
237
220
  change_status('scheduled')
238
221
  delay(run_at: scheduled_at).deliver
239
222
  end
223
+
224
+ def scheduled?
225
+ status.to_s.eql?('scheduled')
226
+ end
227
+
228
+ def job
229
+ mailing_jobs.first
230
+ end
240
231
 
232
+ def mailing_jobs
233
+ Delayed::Job.where("handler like ?","%MailManager::Mailing%#{subject}%")
234
+ end
235
+
241
236
  def cancel
242
237
  raise "Unable to cancel" unless can_cancel?
243
238
  change_status('pending')
244
- # Delayed::Job.active.find(:all, :conditions => ["handler like ?","MailMgr::Mailing"])
245
-
246
- #Changing this to return only the jobs that match the id so I don't have to parse with YAML ... seems logical
247
- mailing_jobs = Delayed::Job.find(:all, :conditions => ["handler like ?","%MailMgr::Mailing%"] || ["handler like ?", "%id: {job_mailing_id.to_i}\n%"])
248
- #mailing_jobs = Delayed::Job.active.find(:all, :conditions => ["handler like ?","%MailMgr::Mailing%"])
249
- mailing_jobs.each do |job|
250
- #job_mailing_id = YAML::load(job.handler).object.split(':').last
251
- #logger.debug "Job mailing id: #{job_mailing_id} - This mailing id: #{self.id} - do they match: #{job_mailing_id.to_i == self.id.to_i}"
252
- job.destroy #if job_mailing_id.to_i == self.id.to_i
253
- end
239
+ mailing_jobs.delete_all
254
240
  end
255
-
256
- def resume
257
- raise "Unable to resume" unless can_resume?
258
- change_status('resumed')
241
+
242
+ def pending?
243
+ status.to_s.eql?('pending')
259
244
  end
260
245
 
261
- def pause
262
- raise "Unable to pause" unless can_pause?
263
- change_status('paused')
264
- end
265
246
  end
266
247
  end
@@ -15,7 +15,7 @@ failed - either the message couldn't be handed to the Email Server or it has bee
15
15
  module MailManager
16
16
  class Message < ActiveRecord::Base
17
17
  self.table_name = "#{MailManager.table_prefix}messages"
18
- belongs_to :mailing, :class_name => 'MailManager::Mailing'
18
+ belongs_to :mailing, :class_name => 'MailManager::Mailing', counter_cache: true
19
19
  belongs_to :subscription, :class_name => 'MailManager::Subscription'
20
20
  has_many :bounces, :class_name => 'MailManager::Bounce'
21
21
  belongs_to :contact, :class_name => 'MailManager::Contact'
@@ -28,6 +28,10 @@ module MailManager
28
28
  scope :sent, :conditions => ["status=?", 'sent']
29
29
  scope :processing, :conditions => ["status=?", 'processing']
30
30
 
31
+ before_save :fix_counter_cache, if: lambda {|message| !message.new_record? &&
32
+ message.mailing_id_changed?
33
+ }
34
+
31
35
  attr_protected :id
32
36
 
33
37
  def initialize(*args)
@@ -36,7 +40,7 @@ module MailManager
36
40
  end
37
41
 
38
42
  scope :search, lambda{|params|
39
- conditions = ["1"]
43
+ conditions = ["1=1"]
40
44
  if params[:mailing_id]
41
45
  conditions[0] += " AND #{MailManager.table_prefix}messages.mailing_id=?"
42
46
  conditions << params[:mailing_id]
@@ -56,6 +60,9 @@ module MailManager
56
60
  before_create :set_default_status
57
61
  after_create :generate_guid
58
62
 
63
+ # returns a string in the form of "contact name" <email@example.com> if
64
+ # the contact's full name returns anything ... or simply email@example.com if
65
+ # there is no name at all
59
66
  def email_address_with_name
60
67
  return %Q|"#{full_name}" <#{email_address}>|.gsub(/\s+/,' ') unless full_name.eql?('')
61
68
  email_address
@@ -63,22 +70,50 @@ module MailManager
63
70
 
64
71
  # sends the message through Mailer
65
72
  def deliver
73
+ # lock only needed until status is updated
74
+ Lock.with_lock("deliver_message_#{self.id}") do
75
+ reload
76
+ if can_deliver?
77
+ change_status(:processing)
78
+ else
79
+ Rails.logger.warn "Message(#{self.id})'s is no longer suitable to deliver.. staus: #{status}"
80
+ end
81
+ end
66
82
  MailManager::Mailer.deliver_message(self)
67
83
  change_status(:sent)
84
+ # allow other errors to bubble up
85
+ rescue MailManager::LockException => e
86
+ Rails.logger.warn "Locking error while trying to send MailManager::Message(#{id}) leaving in #{status} status"
87
+ end
88
+
89
+ # whether or not you can deliver a message
90
+ def can_deliver?
91
+ ['ready','pending'].include?(status)
92
+ end
93
+
94
+ # return a contact whether its deleted or not
95
+ def active_or_deleted_contact
96
+ @active_or_deleted_contact ||= self.contact || MailManager::Contact.unscoped.
97
+ where(id: self.contact_id).first
68
98
  end
69
99
 
100
+ # returns the contact's full name
70
101
  def full_name
71
- contact.full_name
102
+ active_or_deleted_contact.try(:full_name)
72
103
  end
73
104
 
105
+ # returns the contact's email address
74
106
  def email_address
75
- contact.email_address
107
+ active_or_deleted_contact.try(:email_address)
76
108
  end
77
109
 
110
+ # returns the mailings subject
78
111
  def subject
79
112
  mailing.subject
80
113
  end
81
114
 
115
+ # the "From: " email address for the email
116
+ # lazy sets the from email addres if not present from the mailing
82
117
  def from_email_address
83
118
  return self[:from_email_address] if self[:from_email_address].present?
84
119
  self.update_attribute(:from_email_address,mailing.from_email_address)
@@ -90,16 +125,18 @@ module MailManager
90
125
  @parts ||= mailing.parts(substitutions)
91
126
  end
92
127
 
128
+ # returns the contact's 'contactable' object tied to the contact
93
129
  def contactable
94
- contact.try(:contactable)
130
+ active_or_deleted_contact.try(:contactable)
95
131
  end
96
132
 
133
+ # returns a hash of substitutions to be used to modify the mailable's html/plaing text
97
134
  def substitutions
98
135
  substitutions_hash = {}
99
136
  MailManager::ContactableRegistry.registered_methods.each do |method|
100
137
  method_key = method.to_s.upcase
101
- if contact.respond_to?(method)
102
- substitutions_hash[method_key] = contact.send(method)
138
+ if active_or_deleted_contact.respond_to?(method)
139
+ substitutions_hash[method_key] = active_or_deleted_contact.send(method)
103
140
  elsif contactable.respond_to?(method)
104
141
  substitutions_hash[method_key] = contactable.send(method)
105
142
  else
@@ -109,6 +146,7 @@ module MailManager
109
146
  substitutions_hash.merge('UNSUBSCRIBE_URL' => unsubscribe_url)
110
147
  end
111
148
 
149
+ # the full url to unsubscribe based on this message; including site url & guid
112
150
  def unsubscribe_url
113
151
  "#{MailManager.site_url}#{MailManager.unsubscribe_path}/#{guid}"
114
152
  end
@@ -116,12 +154,18 @@ module MailManager
116
154
  # generated the guid for which the message is identified by in transit
117
155
  def generate_guid
118
156
  update_attribute(:guid,
119
- "#{contact.id}-#{subscription.try(:id)}-#{self.id}-#{Digest::SHA1.hexdigest("#{contact.id}-#{subscription.try(:id)}-#{self.id}-#{MailManager.secret}")}")
157
+ "#{active_or_deleted_contact.try(:id)}-#{subscription.try(:id)}-#{self.id}-#{Digest::SHA1.hexdigest("#{active_or_deleted_contact.try(:id)}-#{subscription.try(:id)}-#{self.id}-#{MailManager.secret}")}")
120
158
  end
121
159
 
122
160
  protected
161
+ # nodoc: set the type on create
123
162
  def set_type
124
163
  self[:type] = self.class.name
125
164
  end
165
+
166
+ def fix_counter_cache
167
+ MailManager::Mailing.decrement_counter(:messages_count, self.mailing_id_was) if self.mailing_id_was.present?
168
+ MailManager::Mailing.increment_counter(:messages_count, self.mailing_id)
169
+ end
126
170
  end
127
171
  end
@@ -83,6 +83,10 @@ module MailManager
83
83
  status.eql?('active')
84
84
  end
85
85
 
86
+ def pending?
87
+ status.eql?('pending')
88
+ end
89
+
86
90
  # unsubscribes a contact from all lists by looking them up through a messages GUID
87
91
  # FIXME: when we add more lists and the ability to have multiple subscriptions, this should
88
92
  # remove only the list that is tied in the GUID and they should be linked to their options
@@ -91,8 +95,7 @@ module MailManager
91
95
  contact = message.contact
92
96
  if message
93
97
  begin
94
- unsubscribed_subscriptions = self.unsubscribe_by_email_address(message.contact.email_address)
95
- Mailer.deliver_unsubscribed(message,unsubscribed_subscriptions) unless unsubscribed_subscriptions.empty?
98
+ unsubscribed_subscriptions = self.unsubscribe_by_email_address(message.contact.email_address, message)
96
99
  return unsubscribed_subscriptions
97
100
  rescue => e
98
101
  Rails.logger.warn "Error Unsubscribing email: #{message.contact.email_address}\n#{e.message}\n #{e.backtrace.join("\n ")}"
@@ -112,13 +115,16 @@ module MailManager
112
115
  end
113
116
  end
114
117
 
115
- def self.unsubscribe_by_email_address(email_address)
118
+ def self.unsubscribe_by_email_address(email_address,message=nil)
116
119
  subscriptions = []
117
120
  Contact.find_all_by_email_address(email_address).each do |contact|
118
121
  subscriptions += contact.active_subscriptions.each do |subscription|
119
122
  subscription.change_status(:unsubscribed)
120
123
  end
121
124
  end
125
+ Mailer.delay.unsubscribed(subscriptions,email_address,
126
+ subscriptions.first.contact, message) if \
127
+ subscriptions.present?
122
128
  subscriptions
123
129
  end
124
130
  end
@@ -37,7 +37,8 @@ module StatusHistory
37
37
 
38
38
  def status
39
39
  return self[:status].to_s unless self[:status].blank?
40
- self[:status] = default_status
40
+ set_default_status
41
+ self[:status]
41
42
  end
42
43
 
43
44
  def status=(new_status)
@@ -50,7 +51,7 @@ module StatusHistory
50
51
  end
51
52
 
52
53
  def set_default_status
53
- return unless status.blank?
54
+ return unless self[:status].blank?
54
55
  self[:status_changed_at] = Time.now.utc
55
56
  self[:status] = default_status
56
57
  Rails.logger.debug "Setting Default Status to #{default_status} #{self.name rescue "Not a class?"} #{self.class.name}"
@@ -1,14 +1,42 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html lang='en'>
3
3
  <head>
4
- <title>MailManager</title>
4
+ <!-- iReach application.html.rb -->
5
+ <title><%= h(yield(:title) || "iReach Newsletter Manager") %></title>
5
6
  <%= stylesheet_link_tag "mail_manager/application", :media => "all" %>
7
+ <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/le-frog/jquery-ui.css" media="screen" rel="stylesheet" type="text/css" />
6
8
  <%= javascript_include_tag "mail_manager/application" %>
7
9
  <%= csrf_meta_tags %>
10
+ <%= content_for :head %>
8
11
  </head>
9
12
  <body>
10
-
11
- <%= yield %>
12
-
13
+ <div id="top"><%= image_tag "mail_manager/iReach_logo.gif", width: "269", height:"85", style: "float: left;" %><%= image_tag "mail_manager/TopCenter.gif", width: "435", height: "85", style: "float: left;" %><%= image_tag "mail_manager/TopRight.gif", width: "62", height: "85", style: "float: right;" %>&nbsp;</div>
14
+ <div style="background-color: #fff;">
15
+ <div id="menu">
16
+ <ul>
17
+ <li><span onClick="$('#mailings_submenu').toggle();return false">Mailings</span>
18
+ <ul id='mailings_submenu' <%= ' style="display:none"' unless request.path =~ %r|/mail_manager| %>>
19
+ <%= content_tag(:li, link_to('Contacts', mail_manager.contacts_path)) if can?(:manage, MailManager::Contact) %>
20
+ <%= content_tag(:li, link_to('Mailings', mail_manager.mailings_path)) if can?(:manage, MailManager::Mailing) %>
21
+ <%= content_tag(:li, link_to('Mailing Lists', mail_manager.mailing_lists_path)) if can?(:manage, MailManager::MailingList) %>
22
+ <%= content_tag(:li, link_to('Bounces', mail_manager.bounces_path)) if can?(:manage, MailManager::Bounce) %>
23
+ </ul>
24
+ </li>
25
+ </ul>
26
+ </div>
27
+ <div id="page_content">
28
+ <% flash.each do |name, msg| -%>
29
+ <%= content_tag :div, msg, :id => "flash_#{name}" %>
30
+ <% end -%>
31
+
32
+ <% if show_title? -%>
33
+ <h1><%=h yield(:title) %></h1>
34
+ <% end -%>
35
+ <%= yield %>
36
+
37
+ <%= yield :page_navigation %>
38
+ </div>
39
+ </div>
40
+ <%= image_tag "mail_manager/BottomRight.gif", width: "62", height: "85", style: "float: right;" %>
13
41
  </body>
14
42
  </html>
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang='en'>
3
+ <head>
4
+ <title>IReach Newsletter Archive</title>
5
+ </head>
6
+ <body>
7
+ <div id="top"><%= image_tag "mail_manager/iReach_logo.gif", width: "269", height:"85" %></div>
8
+ <div id="page_content">
9
+ <% flash.each do |name, msg| -%>
10
+ <%= content_tag :div, msg, :id => "flash_#{name}" %>
11
+ <% end -%>
12
+ <%= yield %>
13
+ </div>
14
+ </body>
15
+ </html>
@@ -1,9 +1,9 @@
1
- <% title "Listing Bounces for #{@mailing.try(:subject)}" %>
1
+ <%= title "Listing Bounces#{"for #{@mailing.subject}" if @mailing.present?}" %>
2
2
 
3
3
 
4
4
  <%= form_tag mail_manager.bounces_path, :id => 'search_form', :method => 'GET' do %>
5
- Mailing: <%= select_tag "mailing_id", options_for_select(@mailings.collect{|mailing| ["#{mailing.subject} (#{l mailing.status_changed_at}) (#{mailing.bounce_count})",mailing.id.to_s]},params[:mailing_id].to_i), :include_blank => true, :onChange => "$('#search_form').submit()" %></br>
6
- Status:<%= select_tag "bounce[status]", options_for_select([['Needs Attention','needs_manual_intervention'],['Resolved','resolved']],params[:bounce][:status]), :include_blank => true, :onChange => "$('#search_form').submit()" %>
5
+ <label for="mailing_id">Mailing:</label><%= select_tag "mailing_id", options_for_select(@mailings.collect{|mailing| ["#{mailing.subject} (#{l mailing.status_changed_at if mailing.status_changed_at.present?}) (#{mailing.bounces.size})",mailing.id.to_s]},params[:mailing_id].to_i), :include_blank => true, :onChange => "$('#search_form').submit()" %><br />
6
+ <label for="bounce_status">Status:</label><%= select_tag "bounce[status]", options_for_select([['Needs Attention','needs_manual_intervention'],['Resolved','resolved']],params[:bounce][:status]), :include_blank => true, :onChange => "$('#search_form').submit()" %><br />
7
7
  <% end %>
8
8
  <% if @bounces.length == 0 %>
9
9
  <h3>No bounces found for the Mailing with given status.</h3>
@@ -14,6 +14,7 @@
14
14
  <table class="list" cellpadding="1" cellspacing="0">
15
15
  <tr class="title">
16
16
  <td>Contact</td>
17
+ <td>Status</td>
17
18
  <td>Status changed at</td>
18
19
  <td>Comments</td>
19
20
  <td>&nbsp;</td>
@@ -21,9 +22,10 @@
21
22
  <% for bounce in @bounces %>
22
23
  <tr class="<%= cycle('odd','even') %>">
23
24
  <td><%=h bounce.contact_full_name %> <%=h bounce.contact_email_address %></td>
25
+ <td><%=h bounce.status rescue 'N/A' %></td>
24
26
  <td><%=l bounce.status_changed_at rescue nil %></td>
25
27
  <td><%=h bounce.comments %></td>
26
- <td><%= link_to "View", bounce, :class => 'button' %><div class="linkbuttonEnding"></div></td>
28
+ <td><%= link_to "View", bounce, :id => "view_bounce_#{bounce.id}", :class => 'button' %></td>
27
29
  </tr>
28
30
  <% end %>
29
31
  </table>
@@ -3,9 +3,9 @@
3
3
 
4
4
  <% if @bounce.status.eql?('needs_manual_intervention') %>
5
5
  <div>
6
- <%= link_to "Unsubscribe", mail_manager.fail_address_bounce_path(@bounce), :class => 'button' %><div class="linkbuttonEnding"></div>
6
+ <%= link_to "Unsubscribe", mail_manager.fail_address_bounce_path(@bounce), :class => 'button' %>
7
7
  &nbsp;
8
- <%= link_to "Dismiss", mail_manager.dismiss_bounce_path(@bounce), :class => 'button' %><div class="linkbuttonEnding"></div>
8
+ <%= link_to "Dismiss", mail_manager.dismiss_bounce_path(@bounce), :class => 'button' %>
9
9
  </div>
10
10
  <% end %>
11
11
 
@@ -33,6 +33,6 @@
33
33
  <%= content_for :page_navigation do %>
34
34
  <div>
35
35
  <%= link_to "Back", mail_manager.bounces_path(:mailing_id => @mailing.try(:id),
36
- :bounce => {:status => @bounce.status}), :class => 'button' %><div class="linkbuttonEnding"></div>
36
+ :bounce => {:status => @bounce.status}), :class => 'button' %>
37
37
  </div>
38
38
  <% end %>
@@ -1,27 +1,11 @@
1
1
  <%= form_for @contact do |f| %>
2
2
  <%= f.error_messages %>
3
- <table cellspacing='1' cellpadding='0' border='0' width="400">
4
- <tr valign='top'>
5
- <tr valign="top">
6
- <td width='150'><%= f.label :first_name %></td>
7
- <td><%= f.text_field :first_name %></td>
8
- </tr>
9
- <tr valign='top'>
10
- <tr valign="top">
11
- <td width='150'><%= f.label :last_name %></td>
12
- <td><%= f.text_field :last_name %></td>
13
- </tr>
14
- <tr valign='top'>
15
- <tr valign="top">
16
- <td width='150'><%= f.label :email_address %></td>
17
- <td><%= f.text_field :email_address %></td>
18
- </tr>
19
- </table>
20
- <table cellspacing='1' cellpadding='0' border='0' width="400">
3
+ <%= f.label :first_name %>
4
+ <%= f.text_field :first_name, :style => 'width: 300px;' %><br />
5
+ <%= f.label :last_name %>
6
+ <%= f.text_field :last_name, :style => 'width: 300px;' %><br />
7
+ <%= f.label :email_address %>
8
+ <%= f.text_field :email_address, :style => 'width: 300px;' %><br />
21
9
  <%= contactable_subscriptions_selector(f) %>
22
- <tr valign='top'>
23
- <td align="right" colspan="2"><%= f.submit "Submit", :class => 'button' %><div class="buttonEnding"></div></td>
24
- </tr>
25
- </table>
26
-
10
+ <div class="submit_button"><%= f.submit "Submit", :class => 'button' %></div>
27
11
  <% end %>