mail_manager 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.DS_Store +0 -0
- data/.gitignore +20 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +27 -0
- data/Guardfile +24 -0
- data/LICENSE.txt +22 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +141 -0
- data/Procfile +4 -0
- data/README +243 -0
- data/README.md +29 -0
- data/README.rdoc +3 -0
- data/Rakefile +33 -0
- data/app/.DS_Store +0 -0
- data/app/assets/javascripts/mail_manager/application.js +15 -0
- data/app/assets/stylesheets/mail_manager/application.css +13 -0
- data/app/controllers/mail_manager/application_controller.rb +4 -0
- data/app/controllers/mail_manager/base_controller.rb +22 -0
- data/app/controllers/mail_manager/bounces_controller.rb +32 -0
- data/app/controllers/mail_manager/contacts_controller.rb +75 -0
- data/app/controllers/mail_manager/mailing_lists_controller.rb +49 -0
- data/app/controllers/mail_manager/mailings_controller.rb +102 -0
- data/app/controllers/mail_manager/messages_controller.rb +30 -0
- data/app/controllers/mail_manager/subscriptions_controller.rb +104 -0
- data/app/helpers/mail_manager/application_helper.rb +4 -0
- data/app/helpers/mail_manager/subscriptions_helper.rb +8 -0
- data/app/models/.DS_Store +0 -0
- data/app/models/mail_manager.rb +12 -0
- data/app/models/mail_manager/bounce.rb +133 -0
- data/app/models/mail_manager/contact.rb +91 -0
- data/app/models/mail_manager/contactable_registry.rb +190 -0
- data/app/models/mail_manager/mailable_registry.rb +127 -0
- data/app/models/mail_manager/mailer.rb +267 -0
- data/app/models/mail_manager/mailing.rb +266 -0
- data/app/models/mail_manager/mailing_list.rb +36 -0
- data/app/models/mail_manager/message.rb +127 -0
- data/app/models/mail_manager/subscription.rb +126 -0
- data/app/models/mail_manager/test_message.rb +175 -0
- data/app/models/status_history.rb +60 -0
- data/app/views/layouts/mail_manager/application.html.erb +14 -0
- data/app/views/mail_manager/bounces/_email_parts.html.erb +30 -0
- data/app/views/mail_manager/bounces/index.html.erb +32 -0
- data/app/views/mail_manager/bounces/show.html.erb +38 -0
- data/app/views/mail_manager/contacts/_form.html.erb +27 -0
- data/app/views/mail_manager/contacts/double_opt_in.html.erb +1 -0
- data/app/views/mail_manager/contacts/edit.html.erb +12 -0
- data/app/views/mail_manager/contacts/index.html.erb +86 -0
- data/app/views/mail_manager/contacts/new.html.erb +9 -0
- data/app/views/mail_manager/contacts/show.html.erb +22 -0
- data/app/views/mail_manager/contacts/subscribe.html.erb +2 -0
- data/app/views/mail_manager/contacts/thank_you.html.erb +12 -0
- data/app/views/mail_manager/help/_available_email_substitutions.html.erb +5 -0
- data/app/views/mail_manager/mailer/double_opt_in.erb +6 -0
- data/app/views/mail_manager/mailer/unsubscribed.erb +5 -0
- data/app/views/mail_manager/mailer/unsubscribed.html.erb +5 -0
- data/app/views/mail_manager/mailing_lists/_form.html.erb +20 -0
- data/app/views/mail_manager/mailing_lists/edit.html.erb +13 -0
- data/app/views/mail_manager/mailing_lists/index.html.erb +39 -0
- data/app/views/mail_manager/mailing_lists/new.html.erb +9 -0
- data/app/views/mail_manager/mailing_lists/show.html.erb +13 -0
- data/app/views/mail_manager/mailings/_form.html.erb +81 -0
- data/app/views/mail_manager/mailings/edit.html.erb +12 -0
- data/app/views/mail_manager/mailings/index.html.erb +52 -0
- data/app/views/mail_manager/mailings/new.html.erb +9 -0
- data/app/views/mail_manager/mailings/show.html.erb +28 -0
- data/app/views/mail_manager/mailings/test.html.erb +12 -0
- data/app/views/mail_manager/messages/index.html.erb +37 -0
- data/app/views/mail_manager/subscriptions/_form.html.erb +37 -0
- data/app/views/mail_manager/subscriptions/_subscriptions.html.erb +13 -0
- data/app/views/mail_manager/subscriptions/edit.html.erb +11 -0
- data/app/views/mail_manager/subscriptions/index.html.erb +32 -0
- data/app/views/mail_manager/subscriptions/new.html.erb +9 -0
- data/app/views/mail_manager/subscriptions/show.html.erb +8 -0
- data/app/views/mail_manager/subscriptions/unsubscribe.html.erb +2 -0
- data/app/views/mail_manager/subscriptions/unsubscribe_by_email_address.html.erb +13 -0
- data/config/daemons.yml +5 -0
- data/config/routes.rb +43 -0
- data/db/migrate/001_mail_mgr_initial.rb +84 -0
- data/db/migrate/002_mail_mgr_create_contact.rb +60 -0
- data/db/migrate/003_mail_mgr_test_message.rb +23 -0
- data/db/migrate/004_add_deleted_at_to_mailing_lists.rb +15 -0
- data/db/migrate/005_contacts_deleted_at.rb +15 -0
- data/db/migrate/006_mail_mgr_mailing_list_add_defaults_to_active.rb +15 -0
- data/db/migrate/007_mail_mgr_message_add_from_email_address.rb +15 -0
- data/db/mlm_migrate/001_mlm_initial.rb +67 -0
- data/db/mlm_migrate/002_mailable_as_polymorphic.rb +27 -0
- data/db/mlm_migrate/003_contact_as_polymorphic.rb +64 -0
- data/db/mlm_migrate/004_bounce_mlm_mailing_id.rb +26 -0
- data/db/mlm_migrate/005_mlm_to_mail_mgr_scoped.rb +29 -0
- data/engine_plan.rb +13 -0
- data/features/bounce_management.feature +0 -0
- data/features/contact_management.feature +24 -0
- data/features/mailable.feature +23 -0
- data/features/mailing_management.feature +78 -0
- data/features/message.feature +11 -0
- data/features/step_definitions/email_steps.rb +50 -0
- data/features/step_definitions/mlm_steps.rb +11 -0
- data/features/step_definitions/pickle_steps.rb +41 -0
- data/features/step_definitions/webrat_steps.rb +115 -0
- data/features/subscription_management.feature +17 -0
- data/features/support/env.rb +31 -0
- data/features/support/paths.rb +44 -0
- data/lib/daemons/mail_manager.rb +38 -0
- data/lib/daemons/mail_manager_ctl +15 -0
- data/lib/deleteable.rb +50 -0
- data/lib/lock.rb +36 -0
- data/lib/mail_manager.rb +5 -0
- data/lib/mail_manager/config.rb +50 -0
- data/lib/mail_manager/engine.rb +43 -0
- data/lib/mail_manager/version.rb +3 -0
- data/lib/tasks/mail_manager.rake +143 -0
- data/lib/tasks/mail_manager_tasks.rake +4 -0
- data/lib/tasks/rspec.rake +165 -0
- data/lib/workers/mail_manager/bounce_job.rb +52 -0
- data/lib/workers/mail_manager/mailing_job.rb +30 -0
- data/lib/workers/mail_manager/message_job.rb +38 -0
- data/lib/workers/mail_manager/test_message_job.rb +37 -0
- data/mail_manager.gemspec +29 -0
- data/script/rails +8 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/test_app/README.rdoc +261 -0
- data/spec/test_app/Rakefile +7 -0
- data/spec/test_app/app/assets/javascripts/application.js +15 -0
- data/spec/test_app/app/assets/javascripts/users.js +2 -0
- data/spec/test_app/app/assets/stylesheets/application.css +13 -0
- data/spec/test_app/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/test_app/app/assets/stylesheets/users.css +4 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/controllers/users_controller.rb +83 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/helpers/users_helper.rb +2 -0
- data/spec/test_app/app/models/user.rb +13 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/app/views/users/_form.html.erb +33 -0
- data/spec/test_app/app/views/users/edit.html.erb +6 -0
- data/spec/test_app/app/views/users/index.html.erb +29 -0
- data/spec/test_app/app/views/users/new.html.erb +5 -0
- data/spec/test_app/app/views/users/show.html.erb +25 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/config/application.rb +65 -0
- data/spec/test_app/config/boot.rb +10 -0
- data/spec/test_app/config/database.yml +25 -0
- data/spec/test_app/config/environment.rb +14 -0
- data/spec/test_app/config/environments/development.rb +37 -0
- data/spec/test_app/config/environments/production.rb +67 -0
- data/spec/test_app/config/environments/test.rb +37 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/inflections.rb +15 -0
- data/spec/test_app/config/initializers/mime_types.rb +5 -0
- data/spec/test_app/config/initializers/secret_token.rb +7 -0
- data/spec/test_app/config/initializers/session_store.rb +8 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +5 -0
- data/spec/test_app/config/lockable.yml +3 -0
- data/spec/test_app/config/mail_manager.yml +21 -0
- data/spec/test_app/config/routes.rb +7 -0
- data/spec/test_app/db/migrate/20131217101010_create_users.rb +13 -0
- data/spec/test_app/db/migrate/20131221064151_mail_mgr_initial.rb +84 -0
- data/spec/test_app/db/migrate/20131221064152_mail_mgr_create_contact.rb +60 -0
- data/spec/test_app/db/migrate/20131221064153_mail_mgr_test_message.rb +23 -0
- data/spec/test_app/db/migrate/20131221064154_add_deleted_at_to_mailing_lists.rb +15 -0
- data/spec/test_app/db/migrate/20131221064155_contacts_deleted_at.rb +15 -0
- data/spec/test_app/db/migrate/20131221064156_mail_mgr_mailing_list_add_defaults_to_active.rb +15 -0
- data/spec/test_app/db/migrate/20131221064157_mail_mgr_message_add_from_email_address.rb +15 -0
- data/spec/test_app/db/migrate/20131221072600_create_delayed_jobs.rb +22 -0
- data/spec/test_app/db/schema.rb +131 -0
- data/spec/test_app/db/structure.sql +31 -0
- data/spec/test_app/public/404.html +26 -0
- data/spec/test_app/public/422.html +26 -0
- data/spec/test_app/public/500.html +25 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/test_app/script/delayed_job +5 -0
- data/spec/test_app/script/lockable +36 -0
- data/spec/test_app/script/rails +6 -0
- data/spec/test_app/spec/controllers/users_controller_spec.rb +160 -0
- data/spec/test_app/spec/factories/mailing_lists.rb +7 -0
- data/spec/test_app/spec/factories/mailings.rb +6 -0
- data/spec/test_app/spec/factories/original_factories.rb.txt +107 -0
- data/spec/test_app/spec/factories/users.rb +10 -0
- data/spec/test_app/spec/models/mail_manager/bounce_spec.rb +17 -0
- data/spec/test_app/spec/models/mail_manager/mailing_list_spec.rb +15 -0
- data/spec/test_app/spec/models/user_spec.rb +37 -0
- data/spec/test_app/spec/requests/users_spec.rb +11 -0
- data/spec/test_app/spec/routing/users_routing_spec.rb +35 -0
- data/spec/test_app/spec/support/database_cleaner.rb +23 -0
- data/spec/test_app/spec/support/files/bad_utf8_chars.eml +32 -0
- data/spec/test_app/spec/views/users/edit.html.erb_spec.rb +24 -0
- data/spec/test_app/spec/views/users/index.html.erb_spec.rb +29 -0
- data/spec/test_app/spec/views/users/new.html.erb_spec.rb +24 -0
- data/spec/test_app/spec/views/users/show.html.erb_spec.rb +21 -0
- data/zeus.json +22 -0
- metadata +424 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
=begin rdoc
|
|
2
|
+
Author:: Chris Hauboldt (mailto:biz@lnstar.com)
|
|
3
|
+
Copyright:: 2009 Lone Star Internet Inc.
|
|
4
|
+
|
|
5
|
+
MailingList simply defines the available lists for subscriptions in the system. See Subscription for more information.
|
|
6
|
+
|
|
7
|
+
=end
|
|
8
|
+
module MailManager
|
|
9
|
+
class MailingList < ActiveRecord::Base
|
|
10
|
+
|
|
11
|
+
self.table_name = "#{MailManager.table_prefix}mailing_lists"
|
|
12
|
+
|
|
13
|
+
# associations get stupid when ActiveRecord is scoped for some horrible reason
|
|
14
|
+
has_many :subscriptions, :class_name => 'MailManager::Subscription'
|
|
15
|
+
has_and_belongs_to_many :mailings, :class_name => 'MailManager::Mailing',
|
|
16
|
+
:join_table => "#{MailManager.table_prefix}mailing_lists_#{MailManager.table_prefix}mailings"
|
|
17
|
+
|
|
18
|
+
scope :active, {:conditions => {:status => 'active',:deleted_at => nil}}
|
|
19
|
+
|
|
20
|
+
validates :name, presence: true
|
|
21
|
+
|
|
22
|
+
include StatusHistory
|
|
23
|
+
before_create :set_default_status
|
|
24
|
+
|
|
25
|
+
attr_protected :id
|
|
26
|
+
|
|
27
|
+
def active?
|
|
28
|
+
deleted_at.nil?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def inactive?
|
|
32
|
+
!active?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
=begin rdoc
|
|
2
|
+
Author:: Chris Hauboldt (mailto:biz@lnstar.com)
|
|
3
|
+
Copyright:: 2009 Lone Star Internet Inc.
|
|
4
|
+
|
|
5
|
+
Message is used in sending a message from an Mailing and keeping state of the message. Generates a "GUID" which is sent in the email and used to identify it in bounces.
|
|
6
|
+
|
|
7
|
+
Statuses:
|
|
8
|
+
pending - MailingJob has created the message but it has not yet been sent
|
|
9
|
+
processing - MailingJob is in process of sending the message
|
|
10
|
+
sent - MailingJob has successfully sent the message to the Email Server
|
|
11
|
+
failed - either the message couldn't be handed to the Email Server or it has been bounced as a permanent failure
|
|
12
|
+
|
|
13
|
+
=end
|
|
14
|
+
|
|
15
|
+
module MailManager
|
|
16
|
+
class Message < ActiveRecord::Base
|
|
17
|
+
self.table_name = "#{MailManager.table_prefix}messages"
|
|
18
|
+
belongs_to :mailing, :class_name => 'MailManager::Mailing'
|
|
19
|
+
belongs_to :subscription, :class_name => 'MailManager::Subscription'
|
|
20
|
+
has_many :bounces, :class_name => 'MailManager::Bounce'
|
|
21
|
+
belongs_to :contact, :class_name => 'MailManager::Contact'
|
|
22
|
+
#FIXME: if we add more types ... change the base message to be MailingMessage or something and don't use
|
|
23
|
+
#me as a message type
|
|
24
|
+
default_scope :conditions => {:type => "MailManager::#{(self.class.name.eql?('Class') ? self.name : self.class.name).gsub(/^MailManager::/,'')}" }
|
|
25
|
+
|
|
26
|
+
scope :pending, {:conditions => {:status => 'pending'}}
|
|
27
|
+
scope :ready, :conditions => ["status=?", 'ready']
|
|
28
|
+
scope :sent, :conditions => ["status=?", 'sent']
|
|
29
|
+
scope :processing, :conditions => ["status=?", 'processing']
|
|
30
|
+
|
|
31
|
+
attr_protected :id
|
|
32
|
+
|
|
33
|
+
def initialize(*args)
|
|
34
|
+
super
|
|
35
|
+
set_type
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
scope :search, lambda{|params|
|
|
39
|
+
conditions = ["1"]
|
|
40
|
+
if params[:mailing_id]
|
|
41
|
+
conditions[0] += " AND #{MailManager.table_prefix}messages.mailing_id=?"
|
|
42
|
+
conditions << params[:mailing_id]
|
|
43
|
+
end
|
|
44
|
+
if params[:status]
|
|
45
|
+
conditions[0] += " AND #{MailManager.table_prefix}messages.status=?"
|
|
46
|
+
conditions << params[:status]
|
|
47
|
+
end
|
|
48
|
+
{
|
|
49
|
+
:conditions => conditions,
|
|
50
|
+
:order => "#{MailManager.table_prefix}contacts.last_name, #{MailManager.table_prefix}contacts.first_name, #{MailManager.table_prefix}contacts.email_address",
|
|
51
|
+
:joins => " INNER JOIN #{MailManager.table_prefix}contacts on #{MailManager.table_prefix}messages.contact_id=#{MailManager.table_prefix}contacts.id"
|
|
52
|
+
}}
|
|
53
|
+
|
|
54
|
+
include StatusHistory
|
|
55
|
+
override_statuses(['pending','processing','sent','failed','ready'], 'pending')
|
|
56
|
+
before_create :set_default_status
|
|
57
|
+
after_create :generate_guid
|
|
58
|
+
|
|
59
|
+
def email_address_with_name
|
|
60
|
+
return %Q|"#{full_name}" <#{email_address}>|.gsub(/\s+/,' ') unless full_name.eql?('')
|
|
61
|
+
email_address
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# sends the message through Mailer
|
|
65
|
+
def deliver
|
|
66
|
+
MailManager::Mailer.deliver_message(self)
|
|
67
|
+
change_status(:sent)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def full_name
|
|
71
|
+
contact.full_name
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def email_address
|
|
75
|
+
contact.email_address
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def subject
|
|
79
|
+
mailing.subject
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def from_email_address
|
|
83
|
+
return self[:from_email_address] if self[:from_email_address].present?
|
|
84
|
+
self.update_attribute(:from_email_address,mailing.from_email_address)
|
|
85
|
+
self[:from_email_address]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# returns the separate mime parts of the message's Mailable
|
|
89
|
+
def parts
|
|
90
|
+
@parts ||= mailing.parts(substitutions)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def contactable
|
|
94
|
+
contact.try(:contactable)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def substitutions
|
|
98
|
+
substitutions_hash = {}
|
|
99
|
+
MailManager::ContactableRegistry.registered_methods.each do |method|
|
|
100
|
+
method_key = method.to_s.upcase
|
|
101
|
+
if contact.respond_to?(method)
|
|
102
|
+
substitutions_hash[method_key] = contact.send(method)
|
|
103
|
+
elsif contactable.respond_to?(method)
|
|
104
|
+
substitutions_hash[method_key] = contactable.send(method)
|
|
105
|
+
else
|
|
106
|
+
substitutions_hash[method_key] = ''
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
substitutions_hash.merge('UNSUBSCRIBE_URL' => unsubscribe_url)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def unsubscribe_url
|
|
113
|
+
"#{MailManager.site_url}#{MailManager.unsubscribe_path}/#{guid}"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# generated the guid for which the message is identified by in transit
|
|
117
|
+
def generate_guid
|
|
118
|
+
update_attribute(:guid,
|
|
119
|
+
"#{contact.id}-#{subscription.try(:id)}-#{self.id}-#{Digest::SHA1.hexdigest("#{contact.id}-#{subscription.try(:id)}-#{self.id}-#{MailManager.secret}")}")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
protected
|
|
123
|
+
def set_type
|
|
124
|
+
self[:type] = self.class.name
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
=begin rdoc
|
|
2
|
+
Author:: Chris Hauboldt (mailto:biz@lnstar.com)
|
|
3
|
+
Copyright:: 2009 Lone Star Internet Inc.
|
|
4
|
+
|
|
5
|
+
Subscription ties Contacts to MailingLists and keeps track of subscription preferences or 'status'
|
|
6
|
+
|
|
7
|
+
Statuses:
|
|
8
|
+
'active' - user has an active subscription to list
|
|
9
|
+
'pending' - awaiting user approval through email
|
|
10
|
+
'unsubscribed' - user or admin has unsubscribe user from list
|
|
11
|
+
'failed_address' - BounceJob has detected a 'permanently' fatal email failure - like the account or domain doesn't exist
|
|
12
|
+
|
|
13
|
+
FIXME: currently tied to users table
|
|
14
|
+
=end
|
|
15
|
+
|
|
16
|
+
module MailManager
|
|
17
|
+
class Subscription < ActiveRecord::Base
|
|
18
|
+
self.table_name = "#{MailManager.table_prefix}subscriptions"
|
|
19
|
+
belongs_to :contact, :class_name => 'MailManager::Contact'
|
|
20
|
+
belongs_to :mailing_list, :class_name => 'MailManager::MailingList'
|
|
21
|
+
has_many :messages, :class_name => 'MailManager::Message'
|
|
22
|
+
|
|
23
|
+
validates_presence_of :mailing_list_id
|
|
24
|
+
validates_associated :mailing_list
|
|
25
|
+
|
|
26
|
+
scope :active, :conditions => {:status => 'active'},
|
|
27
|
+
:joins => "INNER JOIN #{MailManager.table_prefix}contacts ON
|
|
28
|
+
#{MailManager.table_prefix}subscriptions.contact_id = #{MailManager.table_prefix}contacts.id
|
|
29
|
+
and #{MailManager.table_prefix}contacts.deleted_at IS NULL"
|
|
30
|
+
|
|
31
|
+
scope :unsubscribed, :conditions => {:status => 'unsubscribed'},
|
|
32
|
+
:joins => "INNER JOIN #{MailManager.table_prefix}contacts ON
|
|
33
|
+
#{MailManager.table_prefix}subscriptions.contact_id = #{MailManager.table_prefix}contacts.id
|
|
34
|
+
and #{MailManager.table_prefix}contacts.deleted_at IS NULL"
|
|
35
|
+
|
|
36
|
+
scope :failed_address, :conditions => {:status => 'failed_address'},
|
|
37
|
+
:joins => "INNER JOIN #{MailManager.table_prefix}contacts ON
|
|
38
|
+
#{MailManager.table_prefix}subscriptions.contact_id = #{MailManager.table_prefix}contacts.id
|
|
39
|
+
and #{MailManager.table_prefix}contacts.deleted_at IS NULL"
|
|
40
|
+
|
|
41
|
+
scope :pending, :conditions => {:status => 'pending'},
|
|
42
|
+
:joins => "INNER JOIN #{MailManager.table_prefix}contacts ON
|
|
43
|
+
#{MailManager.table_prefix}subscriptions.contact_id = #{MailManager.table_prefix}contacts.id
|
|
44
|
+
and #{MailManager.table_prefix}contacts.deleted_at IS NULL"
|
|
45
|
+
|
|
46
|
+
include StatusHistory
|
|
47
|
+
override_statuses(['active','unsubscribed','failed_address','pending','duplicate','admin_unsubscribed'],'pending')
|
|
48
|
+
before_create :set_default_status
|
|
49
|
+
|
|
50
|
+
attr_protected :id
|
|
51
|
+
|
|
52
|
+
#acts_as_audited rescue Rails.logger.warn "Audit Table not defined!"
|
|
53
|
+
|
|
54
|
+
def contact_full_name
|
|
55
|
+
contact.full_name
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# changes or creates a subscription for the given contact and list and assigns the given status
|
|
59
|
+
def self.change_subscription_status(contact, mailing_list, status)
|
|
60
|
+
subscription = self.find_by_contact_id_and_mailing_list_id(contact.id, mailing_list.id)
|
|
61
|
+
return subscription.change_status(status) if subscription
|
|
62
|
+
subscription = Subscription.new
|
|
63
|
+
subscription.contact = contact
|
|
64
|
+
subscription.mailing_list = mailing_list
|
|
65
|
+
subscription.change_status(status)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# subscribes the contact to the list
|
|
69
|
+
def self.subscribe(contact, mailing_list)
|
|
70
|
+
change_subscription_status(contact, mailing_list, 'active')
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# unsubscribes the contact from the list
|
|
74
|
+
def self.unsubscribe(contact, mailing_list)
|
|
75
|
+
change_subscription_status(contact, mailing_list, 'unsubscribed')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def mailing_list_name
|
|
79
|
+
mailing_list.try(:name)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def active?
|
|
83
|
+
status.eql?('active')
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# unsubscribes a contact from all lists by looking them up through a messages GUID
|
|
87
|
+
# FIXME: when we add more lists and the ability to have multiple subscriptions, this should
|
|
88
|
+
# remove only the list that is tied in the GUID and they should be linked to their options
|
|
89
|
+
def self.unsubscribe_by_message_guid(guid)
|
|
90
|
+
message = Message.find_by_guid(guid)
|
|
91
|
+
contact = message.contact
|
|
92
|
+
if message
|
|
93
|
+
begin
|
|
94
|
+
unsubscribed_subscriptions = self.unsubscribe_by_email_address(message.contact.email_address)
|
|
95
|
+
Mailer.deliver_unsubscribed(message,unsubscribed_subscriptions) unless unsubscribed_subscriptions.empty?
|
|
96
|
+
return unsubscribed_subscriptions
|
|
97
|
+
rescue => e
|
|
98
|
+
Rails.logger.warn "Error Unsubscribing email: #{message.contact.email_address}\n#{e.message}\n #{e.backtrace.join("\n ")}"
|
|
99
|
+
raise "An error occured."
|
|
100
|
+
end
|
|
101
|
+
else
|
|
102
|
+
raise "Could not find your subscription!"
|
|
103
|
+
end
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.fail_by_email_address(email_address)
|
|
108
|
+
Contact.find_all_by_email_address(email_address).each do |contact|
|
|
109
|
+
contact.active_subscriptions.each do |subscription|
|
|
110
|
+
subscription.change_status(:failed_address)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def self.unsubscribe_by_email_address(email_address)
|
|
116
|
+
subscriptions = []
|
|
117
|
+
Contact.find_all_by_email_address(email_address).each do |contact|
|
|
118
|
+
subscriptions += contact.active_subscriptions.each do |subscription|
|
|
119
|
+
subscription.change_status(:unsubscribed)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
subscriptions
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
module MailManager
|
|
2
|
+
class TestMessage < ActiveRecord::Base
|
|
3
|
+
self.table_name = "#{MailManager.table_prefix}messages"
|
|
4
|
+
belongs_to :mailing, :class_name => 'MailManager::Mailing'
|
|
5
|
+
belongs_to :subscription, :class_name => 'MailManager::Subscription'
|
|
6
|
+
has_many :bounces, :class_name => 'MailManager::Bounce'
|
|
7
|
+
belongs_to :contact, :class_name => 'MailManager::Contact'
|
|
8
|
+
#FIXME: if we add more types ... change the base message to be MailingMessage or something and don't use
|
|
9
|
+
#me as a message type
|
|
10
|
+
default_scope :conditions => {:type => "MailManager::#{(self.class.name.eql?('Class') ? self.name : self.class.name).gsub(/^MailManager::/,'')}" }
|
|
11
|
+
|
|
12
|
+
scope :pending, {:conditions => {:status => 'pending'}}
|
|
13
|
+
scope :ready, :conditions => ["status=?", 'ready']
|
|
14
|
+
|
|
15
|
+
def initialize(*args)
|
|
16
|
+
super
|
|
17
|
+
set_type
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
include StatusHistory
|
|
21
|
+
override_statuses(['pending','processing','sent','failed','ready'], 'pending')
|
|
22
|
+
|
|
23
|
+
attr_protected :id
|
|
24
|
+
|
|
25
|
+
scope :search, lambda{|params|
|
|
26
|
+
conditions = ["1"]
|
|
27
|
+
if params[:mailing_id]
|
|
28
|
+
conditions[0] += " AND #{MailManager.table_prefix}messages.mailing_id=?"
|
|
29
|
+
conditions << params[:mailing_id]
|
|
30
|
+
end
|
|
31
|
+
if params[:status]
|
|
32
|
+
conditions[0] += " AND #{MailManager.table_prefix}messages.status=?"
|
|
33
|
+
conditions << params[:status]
|
|
34
|
+
end
|
|
35
|
+
{
|
|
36
|
+
:conditions => conditions,
|
|
37
|
+
:order => "#{MailManager.table_prefix}contacts.last_name, #{MailManager.table_prefix}contacts.first_name, #{MailManager.table_prefix}contacts.email_address",
|
|
38
|
+
:joins => " INNER JOIN #{MailManager.table_prefix}contacts on #{MailManager.table_prefix}messages.contact_id=#{MailManager.table_prefix}contacts.id"
|
|
39
|
+
}}
|
|
40
|
+
|
|
41
|
+
before_create :set_default_status
|
|
42
|
+
after_create :generate_guid
|
|
43
|
+
|
|
44
|
+
def email_address_with_name
|
|
45
|
+
return %Q|"#{full_name}" <#{email_address}>|.gsub(/\s+/,' ') unless full_name.eql?('')
|
|
46
|
+
email_address
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# sends the message through Mailer
|
|
50
|
+
def deliver
|
|
51
|
+
MailManager::Mailer.deliver_message(self)
|
|
52
|
+
change_status(:sent)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def full_name
|
|
56
|
+
contact.full_name
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def email_address
|
|
60
|
+
contact.email_address
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def subject
|
|
64
|
+
mailing.subject
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def from_email_address
|
|
68
|
+
return self[:from_email_address] if self[:from_email_address].present?
|
|
69
|
+
self.update_attribute(:from_email_address,mailing.from_email_address)
|
|
70
|
+
self[:from_email_address]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# returns the separate mime parts of the message's Mailable
|
|
74
|
+
def parts
|
|
75
|
+
@parts ||= mailing.parts(substitutions)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def contactable
|
|
79
|
+
contact.try(:contactable)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def substitutions
|
|
83
|
+
substitutions_hash = {}
|
|
84
|
+
MailManager::ContactableRegistry.registered_methods.each do |method|
|
|
85
|
+
method_key = method.to_s.upcase
|
|
86
|
+
if contact.respond_to?(method)
|
|
87
|
+
substitutions_hash[method_key] = contact.send(method)
|
|
88
|
+
elsif contactable.respond_to?(method)
|
|
89
|
+
substitutions_hash[method_key] = contactable.send(method)
|
|
90
|
+
else
|
|
91
|
+
substitutions_hash[method_key] = ''
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
substitutions_hash.merge('UNSUBSCRIBE_URL' => unsubscribe_url)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def unsubscribe_url
|
|
98
|
+
"#{MailManager.site_url}#{MailManager.unsubscribe_path}/#{guid}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.valid_statuses
|
|
102
|
+
['pending','processing','sent','failed','ready']
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def valid_statuses
|
|
106
|
+
['pending','processing','sent','failed','ready']
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# generated the guid for which the message is identified by in transit
|
|
110
|
+
def generate_guid
|
|
111
|
+
update_attribute(:guid,
|
|
112
|
+
"#{contact.id}-#{subscription.try(:id)}-#{self.id}-#{Digest::SHA1.hexdigest("#{contact.id}-#{subscription.try(:id)}-#{self.id}-#{MailManager.secret}")}")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def default_status
|
|
116
|
+
'pending'
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
default_scope :conditions => {:type => "MailManager::#{(self.class.name.eql?('Class') ? self.name : self.class.name).gsub(/^MailManager::/,'')}" }
|
|
120
|
+
|
|
121
|
+
scope :ready, :conditions => ["status=?", 'ready']
|
|
122
|
+
def email_address
|
|
123
|
+
self[:test_email_address]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def email_address_with_name
|
|
127
|
+
"\"Test Guy\" <#{email_address}>"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def default_status
|
|
131
|
+
'ready'
|
|
132
|
+
end
|
|
133
|
+
def generate_guid
|
|
134
|
+
update_attribute(:guid,
|
|
135
|
+
"test-#{self.id}-#{Digest::SHA1.hexdigest("test-#{self.id}-#{MailManager.secret}")}")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def subscription
|
|
139
|
+
Subscription.new(self)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def valid_statuses
|
|
143
|
+
['ready'] + super
|
|
144
|
+
end
|
|
145
|
+
class Subscription
|
|
146
|
+
def initialize(test_message)
|
|
147
|
+
@test_message = test_message
|
|
148
|
+
end
|
|
149
|
+
def contact
|
|
150
|
+
Contact.new(@test_message)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
class Contact
|
|
154
|
+
def initialize(test_message)
|
|
155
|
+
@test_message = test_message
|
|
156
|
+
end
|
|
157
|
+
def full_name
|
|
158
|
+
"#{first_name} #{last_name}".strip
|
|
159
|
+
end
|
|
160
|
+
def first_name
|
|
161
|
+
'Test'
|
|
162
|
+
end
|
|
163
|
+
def last_name
|
|
164
|
+
'Guy'
|
|
165
|
+
end
|
|
166
|
+
def email_address
|
|
167
|
+
@test_message.email_address
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
protected
|
|
171
|
+
def set_type
|
|
172
|
+
self[:type] = self.class.name
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|