mail_manager 3.0.0 → 3.2.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.
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
@@ -1,7 +1,5 @@
1
1
  module MailManager
2
- class MailingListsController < BaseController
3
- before_filter :find_mailing_list, :except => [:new,:create,:index]
4
-
2
+ class MailingListsController < MailManager::ApplicationController
5
3
  def index
6
4
  @mailing_lists = MailingList.active.order("name asc").paginate(:page => params[:page])
7
5
  end
@@ -19,7 +17,7 @@ module MailManager
19
17
  def create
20
18
  @mailing_list = MailingList.new(params[:mailing_list])
21
19
  if @mailing_list.save
22
- flash[:notice] = 'MailingList was successfully created.'
20
+ flash[:notice] = 'Mailing List was successfully created.'
23
21
  redirect_to(mail_manager.mailing_lists_path)
24
22
  else
25
23
  render :action => "new"
@@ -28,7 +26,7 @@ module MailManager
28
26
 
29
27
  def update
30
28
  if @mailing_list.update_attributes(params[:mailing_list])
31
- flash[:notice] = 'MailingList was successfully updated.'
29
+ flash[:notice] = 'Mailing List was successfully updated.'
32
30
  redirect_to(mail_manager.mailing_lists_path)
33
31
  else
34
32
  render :action => "edit"
@@ -37,13 +35,8 @@ module MailManager
37
35
 
38
36
  def destroy
39
37
  @mailing_list.destroy
38
+ flash[:notice] = "Mailing List was deleted."
40
39
  redirect_to(mail_manager.mailing_lists_url)
41
40
  end
42
-
43
- protected
44
-
45
- def find_mailing_list
46
- @mailing_list = MailingList.find(params[:id])
47
- end
48
41
  end
49
- end
42
+ end
@@ -1,12 +1,15 @@
1
1
  module MailManager
2
- class MailingsController < BaseController
2
+ class MailingsController < ::MailManager::ApplicationController
3
3
  before_filter :find_mailing, :except => [:new,:create,:index]
4
4
  before_filter :find_all_mailing_lists, :only => [:new,:create,:edit,:update]
5
5
  before_filter :find_mailables, :only => [:new,:create,:edit,:update]
6
6
  before_filter :get_mailables_for_select, :only => [:new,:create,:edit,:update]
7
7
 
8
+ include DeleteableActions
9
+
8
10
  def index
9
- @mailings = Mailing.all.sort_by{|mailing| mailing.created_at}.reverse
11
+ @mailings = Mailing.order("created_at desc").paginate(page: (params[:page] || 1),
12
+ per_page: (params[:per_page] || 10))
10
13
  end
11
14
 
12
15
  def show
@@ -27,22 +30,24 @@ module MailManager
27
30
  end
28
31
 
29
32
  def schedule
30
- @mailing.schedule
33
+ if @mailing.can_schedule?
34
+ @mailing.schedule
35
+ flash[:info] = "Mailing scheduled."
36
+ else
37
+ flash[:warning] = ""
38
+ if @mailing.scheduled_at.nil?
39
+ flash[:warning] += "Error! You must edit your mailing and set a time for your mailing to run.<br/>"
40
+ end
41
+ if @mailing.status != 'pending'
42
+ flash[:warning] += "Error! Your mailing must be pending in order to schedule it."
43
+ end
44
+ end
31
45
  redirect_to mail_manager.mailings_path
32
46
  end
33
47
 
34
48
  def cancel
35
49
  @mailing.cancel
36
- redirect_to mail_manager.mailings_path
37
- end
38
-
39
- def resume
40
- @mailing.resume
41
- redirect_to mail_manager.mailings_path
42
- end
43
-
44
- def pause
45
- @mailing.pause
50
+ flash[:notice] = "Mailing cancelled."
46
51
  redirect_to mail_manager.mailings_path
47
52
  end
48
53
 
@@ -72,11 +77,6 @@ module MailManager
72
77
  end
73
78
  end
74
79
 
75
- def destroy
76
- @mailing.destroy
77
- redirect_to(mail_manager.mailings_url)
78
- end
79
-
80
80
  protected
81
81
 
82
82
  def find_mailing
@@ -1,14 +1,11 @@
1
1
  module MailManager
2
- class MessagesController < ApplicationController
3
- layout 'admin'
4
- before_filter :find_message, :except => [:new,:create,:index]
2
+ class MessagesController < ::MailManager::ApplicationController
5
3
  before_filter :find_mailing
6
4
 
7
5
  def index
8
6
  params[:message] = Hash.new unless params[:message]
9
- params[:message][:status] = 'failed' if params[:message][:status].nil?
10
7
  search_params = params[:message].merge(:mailing_id => params[:mailing_id])
11
- @valid_statuses = Message.valid_statuses
8
+ @valid_statuses = [['Any Status','']] + Message.valid_statuses.map{|s| [s.capitalize,s]}
12
9
  @messages = Message.search(search_params).paginate(:page => params[:page])
13
10
  end
14
11
 
@@ -17,14 +14,10 @@ module MailManager
17
14
 
18
15
  protected
19
16
 
20
- def find_message
21
- @message = Message.find(params[:id])
22
- end
23
-
24
17
  def find_mailing
25
18
  return @mailing = Mailing.find_by_id(params[:mailing_id]) if params[:mailing_id]
26
19
  return @mailing = @message.message.try(:mailing) if @message
27
20
  nil
28
21
  end
29
22
  end
30
- end
23
+ end
@@ -1,22 +1,15 @@
1
1
  module MailManager
2
- class SubscriptionsController < BaseController
3
- before_filter :find_subscription, :except => [:new,:create,:index,:unsubscribe,:unsubscribe_by_email_address]
4
- before_filter :find_mailing_list
5
- before_filter :find_contact, :except => [:new,:create,:index,:unsubscribe,:unsubscribe_by_email_address]
6
- skip_before_filter :authorize, :only => [:unsubscribe,:unsubscribe_by_email_address]
2
+ class SubscriptionsController < ::MailManager::ApplicationController
3
+ skip_before_filter :authorize_resource
4
+ skip_before_filter :load_resource
7
5
 
8
- def index
9
- params[:search] = Hash.new unless params[:search]
10
- search_params = params[:search].merge(:mailing_list_id => params[:mailing_list_id])
11
- @valid_statuses = Subscription.valid_statuses
12
- @subscriptions = Subscription.search(search_params).paginate(:all, :page => params[:page])
13
- end
14
-
6
+ # unsubscribes an email adress by a message's guid(sent in the link)
15
7
  def unsubscribe
16
- raise "Empty id for#{params[:guid]}" if params[:guid].blank?
8
+ raise "Empty id for #{params[:guid]}" if params[:guid].blank?
17
9
  if params[:guid] =~ /^test/
18
10
  @message = TestMessage.find_by_guid(params[:guid])
19
11
  @mailing_lists = ['Test Mailing List']
12
+ @email_address = @message.test_email_address
20
13
  @contact = Contact.new(:first_name => 'Test', :last_name => 'Guy',
21
14
  :email_address => @message.test_email_address)
22
15
  else
@@ -25,80 +18,28 @@ module MailManager
25
18
  subscription.mailing_list.nil?}.collect{|subscription| subscription.mailing_list.name}
26
19
  @contact = Message.find_by_guid(params[:guid]).try(:contact)
27
20
  raise "Could not find your subscription. Please try unsubscribing with your email address." if @contact.nil?
21
+ @email_address = @contact.email_address
28
22
  end
29
- render 'unsubscribe', :layout => 'layout'
23
+ render 'unsubscribe', :layout => MailManager.public_layout
30
24
  rescue => e
25
+ # :nocov: catastrophic failure... shouldn't happen
31
26
  Rails.logger.warn "Error unsubscribing: #{e.message}\n #{e.backtrace.join("\n ")}"
32
- flash[:error] = e.message
33
- redirect_to mail_manager.unsubscribe_by_email_address_path
27
+ flash[:error] = "We did not recognize that unsubscribe url! Please try unsubscribing with your email address."
28
+ redirect_to main_app.unsubscribe_by_email_address_path
29
+ # :nocov:
34
30
  end
35
31
 
32
+ # prints/executes form for unsubscribing by email address
36
33
  def unsubscribe_by_email_address
37
34
  unless params[:email_address].blank?
38
35
  unsubscribed_subscriptions = Subscription.unsubscribe_by_email_address(params[:email_address])
36
+ @email_address = params[:email_address]
39
37
  @mailing_lists = unsubscribed_subscriptions.reject{|subscription|
40
38
  subscription.mailing_list.nil?}.collect{|subscription| subscription.mailing_list.name}
41
39
  @contact = Contact.new(:email_address => params[:email_address])
42
- return render('unsubscribe', :layout => 'layout')
43
- end
44
- render :layout => 'layout'
45
- end
46
-
47
- def show
48
- end
49
-
50
- def new
51
- @subscription = Subscription.new
52
- @subscription.mailing_list = @mailing_list
53
- @contact = @subscription
54
- end
55
-
56
- def edit
57
- end
58
-
59
- def create
60
- @subscription = Subscription.new(params[:subscription])
61
- @subscription.mailing_list_id = @mailing_list.id
62
- if @subscription.save
63
- flash[:notice] = 'Subscription was successfully created.'
64
- return redirect_to(mail_manager.mailing_list_subscriptions_path(@mailing_list))
65
- else
66
- @contact = @subscription
67
- render :action => "new"
40
+ return render('unsubscribe', :layout => MailManager.public_layout)
68
41
  end
69
- end
70
-
71
- def update
72
- if @subscription.update_attributes(params[:subscription])
73
- @subscription.change_status(params[:subscription][:status])
74
- flash[:notice] = 'Subscription was successfully updated.'
75
- redirect_to(mail_manager.mailing_list_subscriptions_path(@mailing_list))
76
- else
77
- render :action => "edit"
78
- end
79
- end
80
-
81
- def destroy
82
- @subscription.destroy
83
- redirect_to(mail_manager.subscriptions_url)
84
- end
85
-
86
- protected
87
-
88
- def find_subscription
89
- @subscription = Subscription.find(params[:id])
90
- end
91
-
92
- def find_mailing_list
93
- return @mailing_list = @subscription.mailing_list if @subscription
94
- return @mailing_list = MailingList.find_by_id(params[:mailing_list_id]) if params[:mailing_list_id]
95
- return @mailing_list = MailingList.find_by_id(params[:subscription][:mailing_list_id]) if
96
- params[:subscription]
97
- nil
98
- end
99
-
100
- def find_contact
101
- @contact = @subscription.contact
42
+ render :layout => MailManager.public_layout
102
43
  end
103
44
  end
104
45
  end
@@ -0,0 +1,43 @@
1
+ module MailManager
2
+ module LayoutHelper
3
+ def title(value=nil, locals={})
4
+ if value.nil?
5
+ @page_title
6
+ else
7
+ @page_title = translate( value, locals)
8
+ "<h1>#{@page_title}</h1>".html_safe
9
+ end
10
+ end
11
+
12
+ def use_show_for_resources?
13
+ ::MailManager.use_show_for_resources
14
+ rescue
15
+ # :nocov: shouldn't happen
16
+ false
17
+ # :nocov:
18
+ end
19
+
20
+ def show_title?
21
+ return @show_title if defined? @show_title
22
+ true
23
+ rescue
24
+ # :nocov: shouldn't happen
25
+ false
26
+ # :nocov:
27
+ end
28
+
29
+ def site_url
30
+ ::MailManager.site_url
31
+ rescue
32
+ # :nocov: shouldn't happen
33
+ "#{default_url_options[:protocol]||'http'}://#{default_url_options[:domain]}"
34
+ # :nocov:
35
+ end
36
+
37
+ def translate(key, options={})
38
+ super(key, options.merge(raise: true))
39
+ rescue I18n::MissingTranslationData
40
+ key
41
+ end
42
+ end
43
+ end
@@ -20,19 +20,24 @@ module MailManager
20
20
  class Bounce < ActiveRecord::Base
21
21
  self.table_name = "#{MailManager.table_prefix}bounces"
22
22
  belongs_to :message, :class_name => 'MailManager::Message'
23
- belongs_to :mailing, :class_name => 'MailManager::Mailing'
23
+ belongs_to :mailing, :class_name => 'MailManager::Mailing', counter_cache: true
24
24
  include StatusHistory
25
25
  override_statuses(['needs_manual_intervention','unprocessed','dismissed','resolved','invalid'],'unprocessed')
26
26
  before_create :set_default_status
27
- default_scope :order => "#{MailManager.table_prefix}contacts.last_name, #{MailManager.table_prefix}contacts.first_name, #{MailManager.table_prefix}contacts.email_address",
28
- :joins =>
29
- "LEFT OUTER JOIN #{MailManager.table_prefix}messages on #{MailManager.table_prefix}bounces.message_id=#{MailManager.table_prefix}messages.id "+
30
- " LEFT OUTER JOIN #{MailManager.table_prefix}contacts on #{MailManager.table_prefix}messages.contact_id=#{MailManager.table_prefix}contacts.id"
27
+ #default_scope :order => "#{MailManager.table_prefix}contacts.last_name, #{MailManager.table_prefix}contacts.first_name, #{MailManager.table_prefix}contacts.email_address",
28
+ # :joins =>
29
+ # "LEFT OUTER JOIN #{MailManager.table_prefix}messages on #{MailManager.table_prefix}bounces.message_id=#{MailManager.table_prefix}messages.id "+
30
+ # " LEFT OUTER JOIN #{MailManager.table_prefix}contacts on #{MailManager.table_prefix}messages.contact_id=#{MailManager.table_prefix}contacts.id"
31
31
  #
32
32
  scope :by_mailing_id, lambda {|mailing_id| where(:mailing_id => mailing_id)}
33
33
  scope :by_status, lambda {|status| where(:status => status.to_s)}
34
34
 
35
+ before_save :fix_counter_cache, if: lambda {|bounce| !bounce.new_record? &&
36
+ bounce.mailing_id_changed?
37
+ }
38
+
35
39
  attr_protected :id
40
+
36
41
  #Parses email contents for bounce resolution
37
42
  def process(force=false)
38
43
  if status.eql?('unprocessed') || force
@@ -129,5 +134,11 @@ module MailManager
129
134
  return @email if @email
130
135
  @email = Mail.new(bounce_message)
131
136
  end
137
+
138
+ protected
139
+ def fix_counter_cache
140
+ MailManager::Mailing.decrement_counter(:bounces_count, self.mailing_id_was) if self.mailing_id_was.present?
141
+ MailManager::Mailing.increment_counter(:bounces_count, self.mailing_id)
142
+ end
132
143
  end
133
144
  end
@@ -66,12 +66,65 @@ module MailManager
66
66
  end
67
67
 
68
68
  def self.signup(params)
69
- contact = MailManager::Contact.active.find_by_email_address(params['email_address'])
69
+ contact = Contact.active.find_by_email_address(params['email_address'])
70
70
  contact ||= Contact.new
71
71
  Rails.logger.debug "Updating contact(#{contact.new_record? ? "New" : contact.id}) params: #{params.inspect}"
72
72
  contact.update_attributes(params)
73
73
  contact
74
74
  end
75
+
76
+ def double_opt_in(mailing_list_ids)
77
+ previously_active_subscriptions = subscriptions.select(&:"active?")
78
+ new_subscriptions = subscriptions.select do |s|
79
+ mailing_list_ids.include?(s.mailing_list_id.to_s)
80
+ end
81
+ if new_subscriptions.present?
82
+ new_subscriptions.each{|subscription| subscription.change_status(:pending)}
83
+ self.delay.deliver_double_opt_in
84
+ end
85
+ nil
86
+ end
87
+
88
+ def deliver_double_opt_in
89
+ Mailer.double_opt_in(self).deliver
90
+ end
91
+
92
+ def double_opt_in_url
93
+ "#{MailManager.site_url}#{MailManager.double_opt_in_path}/#{login_token}"
94
+ end
95
+
96
+ def self.inject_contact_id(token,id)
97
+ token = token.split('')
98
+ id_string = id.to_s.split('')
99
+ new_token = ""
100
+ 0.upto(39) do |index|
101
+ new_token << token.pop
102
+ new_token << id_string.shift unless id_string.blank?
103
+ end
104
+ new_token
105
+ end
106
+
107
+ def self.extract_contact_id(token)
108
+ token = token.split('')
109
+ id_string = ""
110
+ 0.upto(token.length - 41) do |index|
111
+ token.shift
112
+ id_string << token.shift
113
+ end
114
+ id_string.to_i
115
+ end
116
+
117
+ def self.find_by_token(token)
118
+ Contact.find_by_id(Contact::extract_contact_id(token))
119
+ end
120
+
121
+ def login_token
122
+ self[:login_token] ||= generate_login_token
123
+ end
124
+
125
+ def authorized?(token)
126
+ login_token.eql?(token) and login_token_created_at > 2.days.ago
127
+ end
75
128
 
76
129
  def initialize_subscriptions
77
130
  @subscriptions = new_record? ? [] : Subscription.find_all_by_contact_id(self.id)
@@ -87,5 +140,15 @@ module MailManager
87
140
  subscription.mailing_list.nil?}.sort_by{|subscription|
88
141
  subscription.mailing_list.name.downcase}
89
142
  end
143
+
144
+ # generated the token for which an opt-in is emailed
145
+ def generate_login_token
146
+ time = Time.now
147
+ token = Contact::inject_contact_id("#{Digest::SHA1.hexdigest(
148
+ "#{self.id}#{::MailManager.secret}#{time}")}", self.id)
149
+ self.update_attribute(:login_token, token)
150
+ self.update_attribute(:login_token_created_at, time)
151
+ token
152
+ end
90
153
  end
91
154
  end
@@ -0,0 +1,14 @@
1
+ class MailManager::Mailable < ActiveRecord::Base
2
+ attr_accessible :name, :email_text, :email_html
3
+ default_scope where(reusable: true)
4
+ include MailManager::MailableRegistry::Mailable
5
+ end
6
+
7
+ MailManager::MailableRegistry.register('MailManager::Mailable',{
8
+ :find_mailables => :all,
9
+ :name => :name,
10
+ :parts => [
11
+ ['text/plain', :email_text],
12
+ ['text/html', :email_html]
13
+ ]
14
+ })
@@ -12,37 +12,50 @@ mail - knows how to send any message based on the different "mime" parts its giv
12
12
 
13
13
  =end
14
14
 
15
- require 'net/http'
16
- require 'uri'
15
+ require 'open-uri'
17
16
  require "base64"
18
17
  begin
19
18
  require "mini_magick"
20
19
  rescue => e
20
+ # :nocov:
21
21
  require 'rmagick' rescue nil
22
+ # :nocov:
22
23
  end
23
24
 
24
25
 
25
26
  module MailManager
26
27
  class Mailer < ActionMailer::Base
27
- def unsubscribed(message,subscriptions)
28
- @contact = message.contact
29
- @recipients = @contact.email_address
30
- @from = message.from_email_address
31
- @message = message
28
+ # send a confirmation email for unsubscribing
29
+ def unsubscribed(subscriptions,email_address,contact=nil,message=nil)
30
+ @contact = contact
31
+ @email_address = email_address
32
+ @recipients = @email_address
33
+ @from = message.try(:from_email_address) || MailManager.default_from_email_address
32
34
  @mailing_lists = subscriptions.reject{|subscription| subscription.mailing_list.nil?}.
33
35
  collect{|subscription| subscription.mailing_list.name}
34
36
  @subject = "Unsubscribed from #{@mailing_lists.join(',')} at #{MailManager.site_url}"
35
- Rails.logger.debug "Really Sending Unsubscribed from #{@mailing_lists.first} to #{@contact.email_address}"
37
+ Rails.logger.debug "Really Sending Unsubscribed from #{@mailing_lists.first} to #{@email_address}"
38
+ mail(to: @recipients, from: @from, subject: @subject)
39
+ end
40
+
41
+ def double_opt_in(contact)
42
+ @contact = contact
43
+ @recipients = @contact.email_address
44
+ @subject = "Confirm Newsletter Subscription at #{::MailManager.site_url}"
45
+ @from = ::MailManager.signup_email_address
46
+ @mailing_list_names = contact.subscriptions.map(&:mailing_list).map(&:name).join(', ')
47
+ @headers = {'Return-Path' => ::MailManager.bounce['email_address']}
36
48
  mail(to: @recipients, from: @from, subject: @subject)
37
49
  end
38
50
 
39
- # we do special junk ... so lets make them class methods
40
51
  class << self
52
+ # send a mailing related to the message's data
41
53
  def deliver_message(message)
42
54
  self.send_mail(message.subject,message.email_address_with_name,message.from_email_address,
43
55
  message.parts,message.guid,message.mailing.include_images?)
44
56
  end
45
57
 
58
+ # create mailing; parsing html sources for images to attach/include
46
59
  def multipart_with_inline_images(subject,to_email_address,from_email_address,the_parts,message_id=nil,include_images=true)
47
60
  text_source = the_parts.first[1];nil
48
61
  original_html_source = the_parts.last[1];nil
@@ -72,6 +85,7 @@ module MailManager
72
85
  mail
73
86
  end
74
87
 
88
+ # create mailing without fetching image data
75
89
  def multipart_alternative_without_images(subject,to_email_address,from_email_address,the_parts,message_id=nil,include_images=true)
76
90
  text_source = the_parts.first[1];nil
77
91
  original_html_source = the_parts.last[1];nil
@@ -92,6 +106,7 @@ module MailManager
92
106
  mail
93
107
  end
94
108
 
109
+ # send the mailing with the given subject, addresses, and parts
95
110
  def send_mail(subject,to_email_address,from_email_address,the_parts,message_id=nil,include_images=true)
96
111
  include_images = (include_images and !MailManager.dont_include_images_domains.detect{|domain|
97
112
  to_email_address.strip =~ /#{domain}>?$/})
@@ -108,8 +123,11 @@ module MailManager
108
123
  Rails.logger.debug mail.to_s
109
124
  end
110
125
 
126
+ # set mail delivery settings
111
127
  def set_mail_settings(mail)
112
- mail.delivery_method ActionMailer::Base.delivery_method.eql?(:letter_opener) ? :test : ActionMailer::Base.delivery_method
128
+ delivery_method = ActionMailer::Base.delivery_method
129
+ delivery_method = delivery_method.eql?(:letter_opener) ? :test : delivery_method
130
+ mail.delivery_method delivery_method
113
131
  # letter opener blows up!
114
132
  # Ex set options!
115
133
  # mail.delivery_method.settings.merge!( {
@@ -123,25 +141,20 @@ module MailManager
123
141
  # } )
124
142
 
125
143
  mail.delivery_method.settings.merge!(
126
- (case method
144
+ (case delivery_method
127
145
  when :smtp then ActionMailer::Base.smtp_settings
146
+ # :nocov:
128
147
  when :sendmail then ActionMailer::Base.sendmail_settings
148
+ # :nocov:
129
149
  else
130
150
  {}
131
151
  end rescue {})
132
152
  )
133
153
  end
134
154
 
135
- def inline_attachment(params, &block)
136
- params = { :content_type => params } if String === params
137
- params = { :disposition => "inline",
138
- :transfer_encoding => "base64" }.merge(params)
139
- params[:headers] ||= {}
140
- params[:headers]['Content-ID'] = params[:cid]
141
- params
142
- end
143
-
155
+ # return mime type for images by extension
144
156
  def image_mime_types(extension)
157
+ # :nocov:
145
158
  case extension.downcase
146
159
  when 'bmp' then 'image/bmp'
147
160
  when 'cod' then 'image/cis-cod'
@@ -156,13 +169,21 @@ module MailManager
156
169
  when 'tif' then 'image/tiff'
157
170
  when 'tiff' then 'image/tiff'
158
171
  end
172
+ # :nocov:
159
173
  end
160
174
 
175
+ # find the extension for images by inspecting their data
161
176
  def get_extension_from_data(image_data)
162
177
  if defined?(MiniMagick)
163
- MiniMagick::Image.read(image_data)[:format] || ''
178
+ format = ''
179
+ file = Tempfile.new('get-extension','tmp')
180
+ file.close
181
+ File.open(file.path,'wb'){|binfile| binfile.write(image_data)}
182
+ MiniMagick::Image.open(file.path)[:format] || ''
164
183
  elsif defined?(Magick)
184
+ # :nocov: currently on ly mini_magick is tested
165
185
  Magick::Image.from_blob(image_data).first.format || ''
186
+ # :nocov:
166
187
  else
167
188
  ''
168
189
  end
@@ -170,6 +191,8 @@ module MailManager
170
191
  ''
171
192
  end
172
193
 
194
+
195
+ # parses html and retrieves images and inserts them with CID/attachments
173
196
  def inline_html_with_images(html_source)
174
197
  parsed_data = html_source.split(/(<\s*img[^>]+src\s*=\s*["'])([^"']*)(["'])/i)
175
198
  images = Array.new
@@ -200,72 +223,16 @@ module MailManager
200
223
  end
201
224
  raise image_errors unless image_errors.eql?('')
202
225
  [final_html,images]
203
- # related_part = Mail::Part.new do
204
- # body final_html
205
- # end
206
- # images.each do |image|
207
- # related_part.part inline_attachment(image)
208
- # end
209
- # related_part.content_type = 'multipart/related'
210
- # related_part
211
-
212
- # related_part = Mail::Part.new do
213
- # content_type 'multipart/related'
214
- # # content_type 'text/html; charset=UTF-8'
215
- # # body final_html
216
- # end
217
- # related_part.parts << Mail::Part.new do
218
- # content_type 'text/html; charset=UTF-8'
219
- # body final_html
220
- # end
221
- # images.each do |image|
222
- # related_part.attachments[image[:filename]] = image[:body]
223
- # end
224
- # related_part.content_type = 'multipart/related'
225
- # related_part.parts.first.content_type = 'text/html; charset=UTF-8'
226
- # related_part.parts.first.header['Content-Disposition'] = 'inline'
227
-
228
- end
229
-
230
- def local_ips
231
- `/sbin/ifconfig`
232
226
  end
233
227
 
234
- def request_local?(uri_str)
235
- uri = URI.parse(uri_str)
236
- ip_address = `host #{uri.host}`.gsub(/.*has address ([\d\.]+)\s.*/m,"\\1")
237
- local_ips.include?(ip_address)
238
- rescue => e
239
- false
240
- end
241
-
228
+ # fetch the data from a url (used for images)
242
229
  def fetch(uri_str, limit = 10)
243
- # You should choose better exception.
244
- raise ArgumentError, 'HTTP redirect too deep' if limit == 0
245
230
  uri = URI.parse(uri_str)
246
- request = Net::HTTP::Get.new("#{uri.path}#{"?"+uri.query if uri.query.to_s.strip != ''}")
247
-
248
- response = Net::HTTP.start(
249
- uri.host, uri.port,
250
- :use_ssl => uri.scheme == 'https',
251
- :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |https|
252
- https.request(request)
253
- end
254
- case response
255
- when Net::HTTPSuccess then response.body
256
- when Net::HTTPRedirection then fetch(response['location'], limit - 1)
231
+ if uri.scheme.eql?('file')
232
+ File.binread(uri_str.gsub(%r#^file://#,''))
257
233
  else
258
- response.error!
234
+ uri.read
259
235
  end
260
- # CURB version - gem wouldn't install anymore on CentOS
261
- # body = ''
262
- # Curl.get(uri_str) do |http|
263
- # http.follow_location = true
264
- # http.interface = '127.0.0.1' if request_local?(uri_str)
265
- # http.on_success{|response| body = response.body}
266
- # end
267
- # raise Exception.new("Couldn't fetch URL: #{uri_str}") unless body.present?
268
- # body
269
236
  end
270
237
  end
271
238
  end