has_emails 0.0.1 → 0.1.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.
- data/CHANGELOG +8 -0
- data/README +32 -71
- data/Rakefile +8 -8
- data/app/models/email.rb +7 -79
- data/app/models/email_address.rb +32 -110
- data/db/migrate/001_create_email_addresses.rb +4 -13
- data/lib/has_emails/extensions/action_mailer.rb +106 -0
- data/lib/has_emails.rb +50 -77
- data/test/app_root/app/models/empty +0 -0
- data/test/app_root/config/environment.rb +4 -27
- data/test/app_root/db/migrate/001_migrate_has_messages_to_version_2.rb +9 -0
- data/test/app_root/db/migrate/002_migrate_has_emails_to_version_1.rb +9 -0
- data/test/factory.rb +48 -0
- data/test/functional/has_emails_test.rb +139 -0
- data/test/test_helper.rb +5 -68
- data/test/unit/action_mailer_test.rb +57 -0
- data/test/unit/email_address_test.rb +100 -152
- data/test/unit/email_test.rb +26 -86
- metadata +78 -87
- data/app/mailers/application_mailer.rb +0 -85
- data/app/models/email_recipient.rb +0 -78
- data/app/models/email_recipient_build_extension.rb +0 -7
- data/db/bootstrap/events.yml +0 -4
- data/db/bootstrap/states.yml +0 -9
- data/db/migrate/002_add_email_specs.rb +0 -18
- data/db/migrate/003_add_email_recipient_specs.rb +0 -18
- data/test/app_root/app/models/department.rb +0 -2
- data/test/app_root/app/models/user.rb +0 -3
- data/test/app_root/db/migrate/001_create_users.rb +0 -11
- data/test/app_root/db/migrate/002_create_departments.rb +0 -12
- data/test/fixtures/departments.yml +0 -9
- data/test/fixtures/email_addresses.yml +0 -32
- data/test/fixtures/message_recipients.yml +0 -85
- data/test/fixtures/messages.yml +0 -52
- data/test/fixtures/state_changes.yml +0 -128
- data/test/fixtures/users.yml +0 -11
- data/test/unit/application_mailer_test.rb +0 -69
- data/test/unit/email_recipient_test.rb +0 -79
- data/test/unit/has_emails_test.rb +0 -36
- data/test/unit/recipient_extension_test.rb +0 -99
data/CHANGELOG
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
*SVN*
|
2
2
|
|
3
|
+
*0.1.0* (May 5th, 2008)
|
4
|
+
|
5
|
+
* Update to latest has_messages api
|
6
|
+
|
7
|
+
* Simplify by removing support for models other than EmailAddresses in Emails
|
8
|
+
|
9
|
+
* Updated documentation
|
10
|
+
|
3
11
|
*0.0.1* (September 26th, 2007)
|
4
12
|
|
5
13
|
* Refactor has_email_address/has_email_addresses so that new associations for unsent/sent emails isn't created for has_email_address
|
data/README
CHANGED
@@ -1,28 +1,25 @@
|
|
1
1
|
= has_emails
|
2
2
|
|
3
|
-
+has_emails+
|
3
|
+
+has_emails+ demonstrates a reference implementation for sending emails with
|
4
|
+
logging and asynchronous support.
|
4
5
|
|
5
6
|
== Resources
|
6
7
|
|
7
|
-
API
|
8
|
-
|
9
|
-
* http://api.pluginaweek.org/has_emails
|
10
|
-
|
11
8
|
Wiki
|
12
9
|
|
13
10
|
* http://wiki.pluginaweek.org/Has_emails
|
14
11
|
|
15
|
-
|
12
|
+
API
|
16
13
|
|
17
|
-
* http://
|
14
|
+
* http://api.pluginaweek.org/has_emails
|
18
15
|
|
19
|
-
|
16
|
+
Development
|
20
17
|
|
21
|
-
* http://
|
18
|
+
* http://dev.pluginaweek.org/browser/trunk/has_emails
|
22
19
|
|
23
|
-
|
20
|
+
Source
|
24
21
|
|
25
|
-
* http://
|
22
|
+
* http://svn.pluginaweek.org/trunk/has_emails
|
26
23
|
|
27
24
|
== Description
|
28
25
|
|
@@ -33,43 +30,29 @@ web application to send notices and other notifications to users.
|
|
33
30
|
|
34
31
|
Rails already provides ActionMailer as a way of sending emails. However, the
|
35
32
|
framework does not provide an easy way to persist emails, track their status, and
|
36
|
-
process them asynchronously. Designing and building
|
37
|
-
|
38
|
-
|
39
|
-
sending and receiving emails to and between models in your application.
|
33
|
+
process them asynchronously. Designing and building a framework that supports this
|
34
|
+
can be complex and takes away from the business focus. This plugin can help ease
|
35
|
+
that process by demonstrating a complete implementation of these features.
|
40
36
|
|
41
37
|
== Usage
|
42
38
|
|
43
|
-
===
|
44
|
-
|
45
|
-
If you want to use the built-in support for email addresses (using the EmailAddress
|
46
|
-
model), you can add emailing support for users like so:
|
47
|
-
|
48
|
-
class User < ActiveRecord::Base
|
49
|
-
has_email_address
|
50
|
-
# has_email_addresses if you want to support multiple addresses
|
51
|
-
end
|
39
|
+
=== Creating new emails
|
52
40
|
|
53
|
-
|
54
|
-
|
41
|
+
Emails should usually still be created using ActionMailer. However, instead of
|
42
|
+
delivering the emails, you can queue the emails like so:
|
55
43
|
|
56
|
-
|
57
|
-
|
58
|
-
:message_class => 'Email'
|
59
|
-
end
|
44
|
+
Notifier.deliver_signup_notification(david) # sends the email now
|
45
|
+
Notifier.queue_signup_notification(david) # sends the email later (has_emails kicks in)
|
60
46
|
|
61
|
-
|
47
|
+
In addition to queueing emails, you can build them directly like so:
|
62
48
|
|
63
|
-
|
64
|
-
email
|
49
|
+
email_address = EmailAddress.find(123)
|
50
|
+
email = email_address.emails.build
|
51
|
+
email.to EmailAddress.find(456)
|
65
52
|
email.subject = 'Hey!'
|
66
53
|
email.body = 'Does anyone want to go out tonight?'
|
67
54
|
email.deliver!
|
68
55
|
|
69
|
-
As can be seen in the above example, you can use Users, EmailAddresses, or even
|
70
|
-
Strings as recipients in emails. Each will be automatically converted to the
|
71
|
-
EmailRecipient class so that it can be stored in the database.
|
72
|
-
|
73
56
|
=== Replying to emails
|
74
57
|
|
75
58
|
reply = email.reply_to_all
|
@@ -82,49 +65,27 @@ EmailRecipient class so that it can be stored in the database.
|
|
82
65
|
forward.body = 'Interested?'
|
83
66
|
forward.deliver!
|
84
67
|
|
85
|
-
===
|
68
|
+
=== Processing email asynchronously
|
86
69
|
|
87
70
|
In addition to delivering emails immediately, you can also *queue* emails so
|
88
|
-
that an external application processes and delivers them
|
89
|
-
useful when you want to asynchronously send e-mails so that
|
90
|
-
user interface on your web application.
|
91
|
-
|
92
|
-
To queue emails for external processing, you can simply use the <tt>queue!</tt>
|
93
|
-
event, rather than <tt>deliver!</tt>. This will indicate to any external processes
|
94
|
-
that the email is ready to be sent. The external process can then invoke <tt>deliver!</tt>
|
95
|
-
whenever it is ready to send the queued email.
|
71
|
+
that an external application processes and delivers them (as mentioned above).
|
72
|
+
This is especially useful when you want to asynchronously send e-mails so that
|
73
|
+
it doesn't block the user interface on your web application.
|
96
74
|
|
97
|
-
|
75
|
+
To process queued emails, you need an external cron job that checks and sends
|
76
|
+
them like so:
|
98
77
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
rake db:migrate:plugins PLUGIN=has_emails
|
103
|
-
|
104
|
-
or (more ideally) generate a migration file that will integrate into your main
|
105
|
-
application's migration path:
|
106
|
-
|
107
|
-
ruby script/generate plugin_migration has_emails
|
78
|
+
Email.with_state('queued').each do |email|
|
79
|
+
email.deliver!
|
80
|
+
end
|
108
81
|
|
109
82
|
== Testing
|
110
83
|
|
111
|
-
Before you can run any tests, the following
|
84
|
+
Before you can run any tests, the following gem must be installed:
|
112
85
|
* plugin_test_helper[http://wiki.pluginaweek.org/Plugin_test_helper]
|
113
|
-
* dry_validity_assertions[http://wiki.pluginaweek.org/Dry_validity_assertions]
|
114
86
|
|
115
87
|
== Dependencies
|
116
88
|
|
117
|
-
|
89
|
+
* plugins_plus[http://wiki.pluginaweek.org/Plugins_plus]
|
118
90
|
* has_messages[http://wiki.pluginaweek.org/Has_messages]
|
119
|
-
|
120
|
-
This plugin is also a plugin+. That means that it contains a slice of an
|
121
|
-
application, such as models and migrations. To test or use a plugin+, you
|
122
|
-
must have the following plugins/gems installed:
|
123
|
-
* plugin_dependencies[http://wiki.pluginaweek.org/Plugin_dependencies]
|
124
|
-
* loaded_plugins[http://wiki.pluginaweek.org/Loaded_plugins]
|
125
|
-
* appable_plugins[http://wiki.pluginaweek.org/Appable_plugins]
|
126
|
-
* plugin_migrations[http://wiki.pluginaweek.org/Plugin_migrations]
|
127
|
-
|
128
|
-
Instead of installing each individual plugin+ feature, you can install them all
|
129
|
-
at once using the plugins+[http://wiki.pluginaweek.org/Plugins_plus] meta package,
|
130
|
-
which contains all additional features.
|
91
|
+
* state_machine[http://wiki.pluginaweek.org/State_machine]
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake/gempackagetask'
|
|
4
4
|
require 'rake/contrib/sshpublisher'
|
5
5
|
|
6
6
|
PKG_NAME = 'has_emails'
|
7
|
-
PKG_VERSION = '0.0
|
7
|
+
PKG_VERSION = '0.1.0'
|
8
8
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
9
9
|
RUBY_FORGE_PROJECT = 'pluginaweek'
|
10
10
|
|
@@ -31,18 +31,18 @@ spec = Gem::Specification.new do |s|
|
|
31
31
|
s.name = PKG_NAME
|
32
32
|
s.version = PKG_VERSION
|
33
33
|
s.platform = Gem::Platform::RUBY
|
34
|
-
s.summary = '
|
34
|
+
s.summary = 'Demonstrates a reference implementation for sending emails with logging and asynchronous support.'
|
35
35
|
|
36
36
|
s.files = FileList['{app,db,lib,test}/**/*'].to_a + %w(CHANGELOG init.rb MIT-LICENSE Rakefile README)
|
37
37
|
s.require_path = 'lib'
|
38
38
|
s.autorequire = 'has_emails'
|
39
39
|
s.has_rdoc = true
|
40
40
|
s.test_files = Dir['test/**/*_test.rb']
|
41
|
-
s.add_dependency 'has_messages', '>= 0.0
|
42
|
-
s.add_dependency 'validates_as_email_address', '>= 0.0.
|
41
|
+
s.add_dependency 'has_messages', '>= 0.1.0'
|
42
|
+
s.add_dependency 'validates_as_email_address', '>= 0.0.2'
|
43
43
|
|
44
|
-
s.author = 'Aaron Pfeifer
|
45
|
-
s.email = '
|
44
|
+
s.author = 'Aaron Pfeifer'
|
45
|
+
s.email = 'aaron@pluginaweek.org'
|
46
46
|
s.homepage = 'http://www.pluginaweek.org'
|
47
47
|
end
|
48
48
|
|
@@ -54,12 +54,12 @@ end
|
|
54
54
|
|
55
55
|
desc 'Publish the beta gem'
|
56
56
|
task :pgem => [:package] do
|
57
|
-
Rake::SshFilePublisher.new('
|
57
|
+
Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{PKG_FILE_NAME}.gem").upload
|
58
58
|
end
|
59
59
|
|
60
60
|
desc 'Publish the API documentation'
|
61
61
|
task :pdoc => [:rdoc] do
|
62
|
-
Rake::SshDirPublisher.new('
|
62
|
+
Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{PKG_NAME}", 'rdoc').upload
|
63
63
|
end
|
64
64
|
|
65
65
|
desc 'Publish the API docs and gem'
|
data/app/models/email.rb
CHANGED
@@ -1,84 +1,12 @@
|
|
1
1
|
# Represents an email which has been sent to one or more recipients. This is
|
2
|
-
# essentially the same as the Message class, but overrides the
|
3
|
-
#
|
2
|
+
# essentially the same as the Message class, but overrides how the it is
|
3
|
+
# delivered.
|
4
4
|
class Email < Message
|
5
|
-
|
6
|
-
validates_as_email_address :sender_spec,
|
7
|
-
:allow_nil => true
|
8
|
-
|
9
|
-
with_options(
|
10
|
-
:class_name => 'EmailRecipient',
|
11
|
-
:foreign_key => 'message_id',
|
12
|
-
:order => 'position ASC',
|
13
|
-
:dependent => true
|
14
|
-
) do |e|
|
15
|
-
e.has_many :to,
|
16
|
-
:conditions => ['kind = ?', 'to'],
|
17
|
-
:extend => [MessageRecipientToBuildExtension, EmailRecipientBuildExtension]
|
18
|
-
e.has_many :cc,
|
19
|
-
:conditions => ['kind = ?', 'cc'],
|
20
|
-
:extend => [MessageRecipientCcBuildExtension, EmailRecipientBuildExtension]
|
21
|
-
e.has_many :bcc,
|
22
|
-
:conditions => ['kind = ?', 'bcc'],
|
23
|
-
:extend => [MessageRecipientBccBuildExtension, EmailRecipientBuildExtension]
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns the sender of the message. This can be a string if being sent
|
27
|
-
# from an arbitrary e-mail address.
|
28
|
-
def sender_with_spec
|
29
|
-
sender_without_spec || sender_spec
|
30
|
-
end
|
31
|
-
alias_method_chain :sender, :spec
|
32
|
-
|
33
|
-
# If sender is a string, then sets the spec, otherwise uses the original
|
34
|
-
# sender setter
|
35
|
-
def sender_with_spec=(value)
|
36
|
-
self.sender_spec = EmailAddress.convert_from(value).spec
|
37
|
-
self.sender_without_spec = value if !value.is_a?(String)
|
38
|
-
end
|
39
|
-
alias_method_chain :sender=, :spec
|
40
|
-
|
41
|
-
# Converts the sender into an Email Address, whether it be a string,
|
42
|
-
# EmailAddress, or other model type
|
43
|
-
def sender_email_address
|
44
|
-
EmailAddress.convert_from(sender_spec)
|
45
|
-
end
|
46
|
-
|
47
|
-
# The name of the person whose sending the email
|
48
|
-
def sender_name
|
49
|
-
sender_without_spec ? EmailAddress.convert_from(sender_without_spec).name : sender_email_address.name
|
50
|
-
end
|
51
|
-
|
52
|
-
# Returns a string version of the email address plus any name like
|
53
|
-
# "John Doe <john.doe@gmail.com>"..
|
54
|
-
def sender_with_name
|
55
|
-
address = self.email_address
|
56
|
-
address.name = self.name
|
57
|
-
address.with_name
|
58
|
-
end
|
59
|
-
|
60
|
-
# Actually delivers the email to the recipients
|
61
|
-
def deliver
|
62
|
-
ApplicationMailer.deliver_email(self)
|
63
|
-
end
|
64
|
-
|
65
|
-
# Saves the +sender_spec+ in the forwarded message
|
66
|
-
def forward
|
67
|
-
message = super
|
68
|
-
message.sender_spec = sender_spec
|
69
|
-
message
|
70
|
-
end
|
71
|
-
|
72
|
-
# Saves the +sender_spec+ in the replied message
|
73
|
-
def reply
|
74
|
-
message = super
|
75
|
-
message.sender_spec = sender_spec
|
76
|
-
message
|
77
|
-
end
|
5
|
+
after_deliver :deliver_email
|
78
6
|
|
79
7
|
private
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
8
|
+
# Actually delivers the email to the recipients
|
9
|
+
def deliver_email
|
10
|
+
ActionMailer::Base.deliver_email(self)
|
11
|
+
end
|
84
12
|
end
|
data/app/models/email_address.rb
CHANGED
@@ -1,123 +1,45 @@
|
|
1
1
|
# Represents a valid RFC822 email address
|
2
2
|
class EmailAddress < ActiveRecord::Base
|
3
|
+
has_emails
|
4
|
+
|
5
|
+
validates_presence_of :spec
|
6
|
+
validates_as_email_address :spec
|
7
|
+
validates_uniqueness_of :spec,
|
8
|
+
:scope => 'name'
|
9
|
+
|
3
10
|
class << self
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# 3. A record with an +email_address+ association
|
9
|
-
# 4. A record with an +email_addresses+ association (first record will be chosen)
|
10
|
-
#
|
11
|
-
# If an EmailAddress is specified, the same model will be returned. An
|
12
|
-
# ArgumentError is raised if it doesn't match any of the above criteria.
|
13
|
-
def convert_from(record)
|
14
|
-
if record
|
15
|
-
if EmailAddress === record
|
16
|
-
record
|
17
|
-
elsif String === record
|
18
|
-
EmailAddress.new(:spec => record)
|
19
|
-
elsif record.respond_to?(:email_address)
|
20
|
-
if record.email_address.is_a?(String)
|
21
|
-
address = EmailAddress.new(:spec => record.email_address)
|
22
|
-
address.name = record.name if record.respond_to?(:name)
|
23
|
-
address
|
24
|
-
else
|
25
|
-
record.email_address
|
26
|
-
end
|
27
|
-
elsif record.respond_to?(:email_addresses)
|
28
|
-
record.email_addresses.first
|
29
|
-
else
|
30
|
-
raise ArgumentError, "Cannot convert #{record.class} to an EmailAddress"
|
31
|
-
end
|
32
|
-
end
|
11
|
+
# Finds or create an email address based on the given value
|
12
|
+
def find_or_create_by_address(address)
|
13
|
+
name, spec = split_address(address)
|
14
|
+
find_or_create_by_name_and_spec(name, spec)
|
33
15
|
end
|
34
16
|
|
35
|
-
#
|
36
|
-
def
|
37
|
-
|
17
|
+
# Splits the given address into a name and spec
|
18
|
+
def split_address(address)
|
19
|
+
if match = /^(\S.*)\s+<(.*)>$/.match(address)
|
20
|
+
name = match[1]
|
21
|
+
spec = match[2]
|
22
|
+
else
|
23
|
+
spec = address
|
24
|
+
end
|
25
|
+
|
26
|
+
return name, spec
|
38
27
|
end
|
39
28
|
end
|
40
29
|
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
# Add messaging capabilities. This will give us an email_box.
|
47
|
-
has_messages :emails,
|
48
|
-
:message_class => 'Email'
|
49
|
-
belongs_to :emailable,
|
50
|
-
:polymorphic => true
|
51
|
-
|
52
|
-
validates_presence_of :spec
|
53
|
-
|
54
|
-
with_options(:allow_nil => true) do |klass|
|
55
|
-
klass.validates_uniqueness_of :spec
|
56
|
-
klass.validates_as_email_address :spec
|
57
|
-
end
|
58
|
-
|
59
|
-
# The name of the person who owns this email address
|
60
|
-
attr_accessor :name
|
61
|
-
|
62
|
-
# Ensure that the e-mail address has a verification code that can be sent
|
63
|
-
# to the user
|
64
|
-
before_create :set_code_expiry
|
65
|
-
|
66
|
-
state :unverified, :verified
|
67
|
-
|
68
|
-
# Verifies that the email address is valid
|
69
|
-
event :verify do
|
70
|
-
transition_to :verified, :from => :unverified
|
71
|
-
end
|
72
|
-
|
73
|
-
# Sets the full address
|
74
|
-
def spec=(new_spec)
|
75
|
-
@local_name = @domain = nil
|
76
|
-
write_attribute(:spec, new_spec)
|
77
|
-
end
|
78
|
-
|
79
|
-
# The part of the e-mail address before the @
|
80
|
-
def local_name
|
81
|
-
parse_spec if !@local_name
|
82
|
-
@local_name
|
83
|
-
end
|
84
|
-
|
85
|
-
# The part of the e-mail address after the @
|
86
|
-
def domain
|
87
|
-
parse_spec if !@domain
|
88
|
-
@domain
|
89
|
-
end
|
90
|
-
|
91
|
-
# Gets the name of the person whose email address this is. Default is an
|
92
|
-
# empty string. Override this if you want it to appear in with_name
|
93
|
-
def name
|
94
|
-
@name || ''
|
30
|
+
# Sets the value to be used for this email address. This can come in two formats:
|
31
|
+
# * With name - John Doe <john.doe@gmail.com>
|
32
|
+
# * Without name - john.doe@gmail.com
|
33
|
+
def address=(address)
|
34
|
+
self.name, self.spec = self.class.split_address(address)
|
95
35
|
end
|
96
36
|
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
37
|
+
# Generates the value for the email address, including the name associated with
|
38
|
+
# it (if provided). For example,
|
39
|
+
#
|
40
|
+
# e = EmailAddress.new(:name => 'John Doe', :spec => 'john.doe@gmail.com')
|
41
|
+
# e.with_name # => "John Doe <john.doe@gmail.com>"
|
100
42
|
def with_name
|
101
|
-
name.blank? ?
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns the full email address (without the name)
|
105
|
-
def to_s #:nodoc
|
106
|
-
spec
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
# Sets the time at which the verification code will expire
|
111
|
-
def set_code_expiry
|
112
|
-
self.code_expiry = 48.hour.from_now
|
113
|
-
end
|
114
|
-
|
115
|
-
# Parses the current spec and sets +@local_name+ and +@domain+ based on the
|
116
|
-
# matching groups within the regular expression
|
117
|
-
def parse_spec
|
118
|
-
if !@local_name && !@domain && match = RFC822::EmailAddress.match(spec)
|
119
|
-
@local_name = match.captures[0]
|
120
|
-
@domain = match.captures[1]
|
121
|
-
end
|
43
|
+
name.blank? ? spec : "#{name} <#{spec}>"
|
122
44
|
end
|
123
45
|
end
|
@@ -1,23 +1,14 @@
|
|
1
1
|
class CreateEmailAddresses < ActiveRecord::Migration
|
2
2
|
def self.up
|
3
3
|
create_table :email_addresses do |t|
|
4
|
-
t.
|
5
|
-
t.
|
6
|
-
t.
|
7
|
-
t.column :verification_code, :string, :limit => 40
|
8
|
-
t.column :code_expiry, :datetime
|
9
|
-
t.column :created_at, :timestamp, :null => false
|
10
|
-
t.column :updated_at, :datetime, :null => false
|
4
|
+
t.string :spec, :null => false, :limit => 382
|
5
|
+
t.string :name
|
6
|
+
t.timestamps
|
11
7
|
end
|
12
|
-
add_index :email_addresses, :spec, :unique => true
|
13
|
-
add_index :email_addresses, :verification_code, :unique => true
|
14
|
-
|
15
|
-
PluginAWeek::Has::States.migrate_up(:email_addresses)
|
8
|
+
add_index :email_addresses, [:spec, :name], :unique => true
|
16
9
|
end
|
17
10
|
|
18
11
|
def self.down
|
19
|
-
PluginAWeek::Has::States.migrate_down(:email_addresses)
|
20
|
-
|
21
12
|
drop_table :email_addresses
|
22
13
|
end
|
23
14
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module PluginAWeek #:nodoc:
|
2
|
+
module HasEmails
|
3
|
+
module Extensions #:nodoc:
|
4
|
+
#
|
5
|
+
module ActionMailer
|
6
|
+
def self.included(base) #:nodoc:
|
7
|
+
base.class_eval do
|
8
|
+
@@default_subject_prefix = "[#{File.basename(File.expand_path(Rails.root)).camelize}] "
|
9
|
+
cattr_accessor :default_subject_prefix
|
10
|
+
|
11
|
+
# Specify the prefix to use for the subject. This defaults to the
|
12
|
+
# +default_subject_prefix+ specified for ApplicationMailer.
|
13
|
+
adv_attr_accessor :subject_prefix
|
14
|
+
|
15
|
+
include PluginAWeek::HasEmails::Extensions::ActionMailer::InstanceMethods
|
16
|
+
extend PluginAWeek::HasEmails::Extensions::ActionMailer::ClassMethods
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def self.extended(base) #:nodoc:
|
22
|
+
class << base
|
23
|
+
alias_method_chain :method_missing, :has_emails
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Handles calls to queue_*
|
28
|
+
def method_missing_with_has_emails(method_symbol, *parameters)
|
29
|
+
case method_symbol.id2name
|
30
|
+
when /^queue_([_a-z]\w*)/
|
31
|
+
# Queues the mail so that it's processed in the background
|
32
|
+
new($1, *parameters).queue
|
33
|
+
else
|
34
|
+
# Handle the mail delivery as normal
|
35
|
+
method_missing_without_has_emails(method_symbol, *parameters)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module InstanceMethods
|
41
|
+
def self.included(base) #:nodoc:
|
42
|
+
base.class_eval do
|
43
|
+
alias_method_chain :initialize_defaults, :subject_prefix
|
44
|
+
alias_method_chain :subject, :prefix
|
45
|
+
alias_method :subject=, :subject_with_prefix
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets or gets the subject of the email. All subjects are prefixed with a
|
50
|
+
# value indicating the application it is coming from.
|
51
|
+
def subject_with_prefix(*parameters)
|
52
|
+
if parameters.empty?
|
53
|
+
subject_without_prefix
|
54
|
+
else
|
55
|
+
subject_without_prefix(subject_prefix + subject_without_prefix(*parameters))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets the default subject prefix
|
60
|
+
def initialize_defaults_with_subject_prefix(method_name) #:nodoc
|
61
|
+
initialize_defaults_without_subject_prefix(method_name)
|
62
|
+
@subject_prefix ||= ::ActionMailer::Base.default_subject_prefix.dup
|
63
|
+
end
|
64
|
+
|
65
|
+
# Delivers an email based on the content in the specified email
|
66
|
+
def email(email)
|
67
|
+
@from = email.sender.with_name
|
68
|
+
@recipients = email.to.map(&:with_name)
|
69
|
+
@cc = email.cc.map(&:with_name)
|
70
|
+
@bcc = email.bcc.map(&:with_name)
|
71
|
+
@subject = email.subject || ''
|
72
|
+
@body = email.body || ''
|
73
|
+
@sent_on = email.updated_at
|
74
|
+
end
|
75
|
+
|
76
|
+
# Queues the current e-mail that has been constructed
|
77
|
+
def queue
|
78
|
+
Email.transaction do
|
79
|
+
# Create the main email
|
80
|
+
email = Email.new(
|
81
|
+
:sender => EmailAddress.find_or_create_by_address(from),
|
82
|
+
:subject => subject,
|
83
|
+
:body => body,
|
84
|
+
:to => email_addresses_for(:recipients),
|
85
|
+
:cc => email_addresses_for(:cc),
|
86
|
+
:bcc => email_addresses_for(:bcc)
|
87
|
+
)
|
88
|
+
email.queue!
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
# Finds or creates all of the email addresses for the given type of
|
94
|
+
# recipient (can be :recipients, :cc, or :bcc)
|
95
|
+
def email_addresses_for(kind)
|
96
|
+
[send(kind)].flatten.collect {|address| EmailAddress.find_or_create_by_address(address)}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
ActionMailer::Base.class_eval do
|
105
|
+
include PluginAWeek::HasEmails::Extensions::ActionMailer
|
106
|
+
end
|