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.
- checksums.yaml +5 -13
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -1
- data/Gemfile +27 -10
- data/LICENSE.txt +2 -2
- data/MIT-LICENSE +1 -1
- data/README.md +97 -15
- data/{features/bounce_management.feature → app/assets/images/mail_manager/.gitkeep} +0 -0
- data/app/assets/images/mail_manager/BottomRight.gif +0 -0
- data/app/assets/images/mail_manager/MidRight.gif +0 -0
- data/app/assets/images/mail_manager/TopCenter.gif +0 -0
- data/app/assets/images/mail_manager/TopRight.gif +0 -0
- data/app/assets/images/mail_manager/calendar_date_select/calendar.gif +0 -0
- data/app/assets/images/mail_manager/iReach_logo.gif +0 -0
- data/app/assets/images/mail_manager/spacer.gif +0 -0
- data/app/assets/images/mail_manager/topMid.gif +0 -0
- data/app/assets/javascripts/mail_manager/application.js +19 -1
- data/app/assets/javascripts/mail_manager/jquery-ui-timepicker-addon.js +2134 -0
- data/app/assets/stylesheets/mail_manager/admin.css +261 -0
- data/app/assets/stylesheets/mail_manager/application.css +3 -1
- data/app/assets/stylesheets/mail_manager/nav.css +68 -0
- data/app/assets/stylesheets/mail_manager/timepicker.css +11 -0
- data/app/controllers/mail_manager/application_controller.rb +7 -2
- data/app/controllers/mail_manager/bounces_controller.rb +5 -10
- data/app/controllers/mail_manager/contacts_controller.rb +42 -20
- data/app/controllers/mail_manager/mailing_lists_controller.rb +5 -12
- data/app/controllers/mail_manager/mailings_controller.rb +18 -18
- data/app/controllers/mail_manager/messages_controller.rb +3 -10
- data/app/controllers/mail_manager/subscriptions_controller.rb +16 -75
- data/app/helpers/mail_manager/layout_helper.rb +43 -0
- data/app/models/mail_manager/bounce.rb +16 -5
- data/app/models/mail_manager/contact.rb +64 -1
- data/app/models/mail_manager/mailable.rb +14 -0
- data/app/models/mail_manager/mailer.rb +48 -81
- data/app/models/mail_manager/mailing.rb +23 -42
- data/app/models/mail_manager/message.rb +52 -8
- data/app/models/mail_manager/subscription.rb +9 -3
- data/app/models/status_history.rb +3 -2
- data/app/views/layouts/mail_manager/application.html.erb +33 -5
- data/app/views/layouts/mail_manager/layout.html.erb +15 -0
- data/app/views/mail_manager/bounces/index.html.erb +6 -4
- data/app/views/mail_manager/bounces/show.html.erb +3 -3
- data/app/views/mail_manager/contacts/_form.html.erb +7 -23
- data/app/views/mail_manager/contacts/edit.html.erb +3 -3
- data/app/views/mail_manager/contacts/index.html.erb +14 -28
- data/app/views/mail_manager/contacts/new.html.erb +2 -2
- data/app/views/mail_manager/contacts/show.html.erb +5 -5
- data/app/views/mail_manager/contacts/subscribe.html.erb +1 -1
- data/app/views/mail_manager/mailer/double_opt_in.erb +1 -1
- data/app/views/mail_manager/mailer/double_opt_in.html.erb +6 -0
- data/app/views/mail_manager/mailer/unsubscribed.erb +1 -1
- data/app/views/mail_manager/mailer/unsubscribed.html.erb +1 -1
- data/app/views/mail_manager/mailing_lists/_form.html.erb +8 -17
- data/app/views/mail_manager/mailing_lists/edit.html.erb +4 -4
- data/app/views/mail_manager/mailing_lists/index.html.erb +6 -5
- data/app/views/mail_manager/mailing_lists/new.html.erb +3 -3
- data/app/views/mail_manager/mailings/_form.html.erb +22 -44
- data/app/views/mail_manager/mailings/edit.html.erb +3 -3
- data/app/views/mail_manager/mailings/index.html.erb +23 -27
- data/app/views/mail_manager/mailings/new.html.erb +2 -2
- data/app/views/mail_manager/mailings/test.html.erb +3 -3
- data/app/views/mail_manager/messages/index.html.erb +2 -2
- data/app/views/mail_manager/subscriptions/_form.html.erb +1 -1
- data/app/views/mail_manager/subscriptions/_subscriptions.html.erb +2 -2
- data/app/views/mail_manager/subscriptions/edit.html.erb +2 -2
- data/app/views/mail_manager/subscriptions/index.html.erb +3 -3
- data/app/views/mail_manager/subscriptions/new.html.erb +1 -1
- data/app/views/mail_manager/subscriptions/unsubscribe.html.erb +1 -1
- data/app/views/mail_manager/subscriptions/unsubscribe_by_email_address.html.erb +3 -3
- data/config/locales/en.yml +13 -0
- data/config/locales/mailings.en.yml +52 -0
- data/config/routes.rb +21 -19
- data/db/migrate/008_add_bounces_count_to_mailings.rb +14 -0
- data/db/migrate/009_add_messages_count_to_mailings.rb +14 -0
- data/db/migrate/010_add_login_token_to_contact.rb +11 -0
- data/db/migrate/011_add_deleted_at_to_mailing.rb +11 -0
- data/lib/delayed/mailer.rb +9 -5
- data/lib/delayed/status.rb +6 -2
- data/lib/delayed_overrides/worker.rb +21 -0
- data/lib/deleteable.rb +13 -14
- data/lib/mail_manager/config.rb +3 -3
- data/lib/mail_manager/engine.rb +136 -7
- data/lib/mail_manager/lock.rb +1 -0
- data/lib/mail_manager/version.rb +1 -1
- data/lib/tasks/mail_manager.rake +92 -56
- data/mail_manager.gemspec +4 -0
- data/spec/rails_helper.rb +50 -0
- data/spec/spec_helper.rb +87 -48
- data/spec/test_app/.env.development +3 -0
- data/spec/test_app/.env.test +2 -0
- data/spec/test_app/.rspec +1 -0
- data/spec/test_app/Procfile +3 -0
- data/spec/test_app/app/controllers/application_controller.rb +4 -0
- data/spec/test_app/app/models/ability.rb +7 -0
- data/spec/test_app/app/models/user.rb +8 -2
- data/spec/test_app/app/models/user_with_role.rb +22 -0
- data/spec/test_app/config/database.postgres.yml +21 -0
- data/spec/test_app/config/database.sqlite.yml +2 -2
- data/spec/test_app/config/environment.rb +2 -2
- data/spec/test_app/config/environments/test.rb +13 -0
- data/spec/test_app/config/mail_manager.yml +66 -2
- data/spec/test_app/config/routes.rb +0 -1
- data/spec/test_app/db/migrate/20150420163235_add_bounces_count_to_mailings.rb +14 -0
- data/spec/test_app/db/migrate/20150420163804_add_messages_count_to_mailings.rb +14 -0
- data/spec/test_app/db/migrate/20150421151457_add_login_token_to_contact.rb +11 -0
- data/spec/test_app/db/migrate/20150423143754_add_deleted_at_to_mailing.rb +11 -0
- data/spec/test_app/db/schema.rb +10 -5
- data/spec/test_app/db/structure.sql +150 -15
- data/spec/test_app/features/bounce_management.feature +11 -0
- data/spec/test_app/features/contact_management.feature +91 -0
- data/{features → spec/test_app/features}/mailable.feature +3 -1
- data/spec/test_app/features/mailing_list_management.feature +39 -0
- data/spec/test_app/features/mailing_management.feature +60 -0
- data/{features → spec/test_app/features}/message.feature +4 -4
- data/spec/test_app/features/message_management.feature +22 -0
- data/spec/test_app/features/step_definitions/bounce_steps.rb +4 -0
- data/spec/test_app/features/step_definitions/contact_steps.rb +63 -0
- data/spec/test_app/features/step_definitions/debugging_steps.rb +3 -0
- data/spec/test_app/features/step_definitions/email_steps.rb +6 -0
- data/spec/test_app/features/step_definitions/job_steps.rb +25 -0
- data/spec/test_app/features/step_definitions/login_steps.rb +4 -0
- data/spec/test_app/features/step_definitions/mailing_list.rb +17 -0
- data/spec/test_app/features/step_definitions/mailing_steps.rb +51 -0
- data/spec/test_app/features/step_definitions/subscription_steps.rb +26 -0
- data/{features → spec/test_app/features}/step_definitions/webrat_steps.rb +10 -6
- data/spec/test_app/features/subscription_management.feature +62 -0
- data/spec/test_app/features/support/env.rb +37 -0
- data/spec/test_app/features/support/paths.rb +36 -0
- data/spec/test_app/lib/debugging.rb +61 -0
- data/spec/test_app/lib/post_office_manager.rb +71 -0
- data/spec/test_app/public/subscribe.html +40 -0
- data/spec/test_app/script/full_suite +50 -0
- data/spec/test_app/script/post_office +25 -0
- data/spec/test_app/script/rails +20 -0
- data/spec/test_app/script/rspec_multi_db +34 -0
- data/spec/test_app/spec/controllers/mail_manager/bounces_controller_spec.rb +59 -0
- data/spec/test_app/spec/controllers/mail_manager/contacts_controller_spec.rb +178 -0
- data/spec/test_app/spec/controllers/mail_manager/mailing_lists_controller_spec.rb +164 -0
- data/spec/test_app/spec/controllers/mail_manager/mailings_controller_spec.rb +184 -0
- data/spec/test_app/spec/controllers/users_controller_spec.rb +47 -46
- data/spec/test_app/spec/factories/_functions.rb +27 -0
- data/spec/test_app/spec/factories/contacts.rb +7 -0
- data/spec/test_app/spec/factories/mail_manager_bounces.rb +13 -0
- data/spec/test_app/spec/factories/mailable.rb +8 -0
- data/spec/test_app/spec/factories/mailings.rb +7 -1
- data/spec/test_app/spec/factories/message.rb +7 -0
- data/spec/test_app/spec/factories/users.rb +19 -7
- data/spec/test_app/spec/features/mail_manager/bounce_spec.rb +73 -0
- data/spec/test_app/spec/features/mail_manager/double_opt_in_spec.rb +62 -0
- data/spec/test_app/spec/features/mail_manager/mailing_spec.rb +46 -0
- data/spec/test_app/spec/features/navigation_spec.rb +9 -0
- data/spec/test_app/spec/helpers/mail_manager/layout_helper_spec.rb +41 -0
- data/spec/test_app/spec/helpers/mail_manager/subscriptions_helper_spec.rb +14 -0
- data/spec/test_app/spec/models/delayed/mailer_spec.rb +27 -0
- data/spec/test_app/spec/models/delayed/status_job_spec.rb +13 -0
- data/spec/test_app/spec/models/delayed/status_spec.rb +37 -0
- data/spec/test_app/spec/models/mail_manager/bounce_spec.rb +23 -3
- data/spec/test_app/spec/models/mail_manager/engine_spec.rb +79 -0
- data/spec/test_app/spec/models/mail_manager/mailable_spec.rb +10 -0
- data/spec/test_app/spec/models/mail_manager/mailer_spec.rb +35 -3
- data/spec/test_app/spec/models/mail_manager/mailing_list_spec.rb +5 -5
- data/spec/test_app/spec/models/mail_manager/mailing_spec.rb +58 -0
- data/spec/test_app/spec/models/mail_manager/message_spec.rb +112 -0
- data/spec/test_app/spec/models/user_spec.rb +10 -8
- data/spec/test_app/spec/rails_helper.rb +86 -0
- data/spec/test_app/spec/requests/users_spec.rb +3 -3
- data/spec/test_app/spec/routing/mail_manager/bounces_routing_spec.rb +27 -0
- data/spec/test_app/spec/routing/mail_manager/contacts_routing_spec.rb +36 -0
- data/spec/test_app/spec/routing/mail_manager/mailing_lists_routing_spec.rb +36 -0
- data/spec/test_app/spec/routing/mail_manager/mailings_routing_spec.rb +36 -0
- data/spec/test_app/spec/spec_helper.rb +82 -32
- data/spec/test_app/spec/support/continuance.rb +18 -0
- data/spec/test_app/spec/support/custom_matchers.rb +17 -0
- data/spec/test_app/spec/support/database_cleaner.rb +10 -1
- data/spec/test_app/spec/views/mail_manager/bounces/index.html.erb_spec.rb +32 -0
- data/spec/test_app/spec/views/mail_manager/bounces/show.html.erb_spec.rb +12 -0
- data/spec/test_app/spec/views/users/edit.html.erb_spec.rb +8 -5
- data/spec/test_app/spec/views/users/index.html.erb_spec.rb +10 -19
- data/spec/test_app/spec/views/users/new.html.erb_spec.rb +9 -6
- data/spec/test_app/spec/views/users/show.html.erb_spec.rb +8 -9
- metadata +231 -75
- data/.DS_Store +0 -0
- data/README.rdoc +0 -3
- data/app/.DS_Store +0 -0
- data/app/controllers/mail_manager/base_controller.rb +0 -22
- data/app/models/.DS_Store +0 -0
- data/features/contact_management.feature +0 -24
- data/features/mailing_management.feature +0 -78
- data/features/step_definitions/email_steps.rb +0 -50
- data/features/step_definitions/mlm_steps.rb +0 -11
- data/features/step_definitions/pickle_steps.rb +0 -41
- data/features/subscription_management.feature +0 -17
- data/features/support/env.rb +0 -11
- data/features/support/paths.rb +0 -44
- data/lib/tasks/mail_manager_tasks.rake +0 -4
- data/lib/tasks/rspec.rake +0 -165
- data/spec/test_app/bin/cucumber +0 -7
- data/spec/test_app/bin/rails +0 -10
- data/spec/test_app/bin/rake +0 -7
- data/spec/test_app/bin/rspec +0 -7
- data/spec/test_app/bin/spring +0 -18
- data/spec/test_app/spec/routing/users_routing_spec.rb +0 -35
- data/spec/test_app/spec/support/post_office.rb +0 -13
@@ -1,7 +1,5 @@
|
|
1
1
|
module MailManager
|
2
|
-
class MailingListsController <
|
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] = '
|
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] = '
|
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 <
|
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.
|
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.
|
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
|
-
|
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 <
|
3
|
-
|
4
|
-
|
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
|
-
|
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 =>
|
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] =
|
33
|
-
redirect_to
|
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 =>
|
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
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
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 =
|
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 '
|
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
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
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 #{@
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|