pluginaweek-has_emails 0.3.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.rdoc +49 -0
- data/LICENSE +20 -0
- data/README.rdoc +96 -0
- data/Rakefile +98 -0
- data/app/models/email.rb +14 -0
- data/app/models/email_address.rb +62 -0
- data/db/migrate/001_create_email_addresses.rb +14 -0
- data/init.rb +1 -0
- data/lib/has_emails.rb +60 -0
- data/lib/has_emails/extensions/action_mailer.rb +117 -0
- data/test/app_root/config/environment.rb +10 -0
- data/test/app_root/db/migrate/001_migrate_has_messages_to_version_2.rb +18 -0
- data/test/app_root/db/migrate/002_migrate_has_emails_to_version_1.rb +13 -0
- data/test/app_root/vendor/plugins/plugin_tracker/init.rb +5 -0
- data/test/factory.rb +58 -0
- data/test/functional/has_emails_test.rb +139 -0
- data/test/test_helper.rb +13 -0
- data/test/unit/action_mailer_test.rb +53 -0
- data/test/unit/email_address_test.rb +160 -0
- data/test/unit/email_test.rb +29 -0
- metadata +107 -0
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
== master
|
2
|
+
|
3
|
+
== 0.3.0 / 2009-04-19
|
4
|
+
|
5
|
+
* Add compatibility with has_messages 0.4.0 / Rails 2.3
|
6
|
+
|
7
|
+
== 0.2.1 / 2009-01-11
|
8
|
+
|
9
|
+
* Add compatibility with has_messages 0.3.1 / state_machine 0.5.0
|
10
|
+
|
11
|
+
== 0.2.0 / 2008-12-14
|
12
|
+
|
13
|
+
* Remove the PluginAWeek namespace
|
14
|
+
|
15
|
+
== 0.1.4 / 2008-10-26
|
16
|
+
|
17
|
+
* Add compatibility with has_messages 0.2.0
|
18
|
+
* Change how the base module is included to prevent namespacing conflicts
|
19
|
+
|
20
|
+
== 0.1.3 / 2008-09-07
|
21
|
+
|
22
|
+
* Add compatibility with state_machine 0.3.0
|
23
|
+
|
24
|
+
== 0.1.2 / 2008-06-29
|
25
|
+
|
26
|
+
* Add compatibility with has_messages 0.1.2
|
27
|
+
|
28
|
+
== 0.1.1 / 2008-06-22
|
29
|
+
|
30
|
+
* Remove log files from gems
|
31
|
+
|
32
|
+
== 0.1.0 / 2008-05-05
|
33
|
+
|
34
|
+
* Update to latest has_messages api
|
35
|
+
* Simplify by removing support for models other than EmailAddresses in Emails
|
36
|
+
* Updated documentation
|
37
|
+
|
38
|
+
== 0.0.1 / 2007-09-26
|
39
|
+
|
40
|
+
* Refactor has_email_address/has_email_addresses so that new associations for unsent/sent emails isn't created for has_email_address
|
41
|
+
* Add state changes fixtures for tests
|
42
|
+
* Add tests for ApplicationMailer
|
43
|
+
* Add support for tracking the original email address for senders/recipients even if the email address changes on the associated model (i.e. EmailAddress/User/etc.)
|
44
|
+
* Support converting models with an email_address/email_addresses association
|
45
|
+
* Allow the sender of emails to be an arbitrary string email address
|
46
|
+
* Add documentation
|
47
|
+
* Move test fixtures out of the test application root directory
|
48
|
+
* Convert dos newlines to unix newlines
|
49
|
+
* Update against latest changes to has_messages
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2006-2009 Aaron Pfeifer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
= has_emails
|
2
|
+
|
3
|
+
+has_emails+ demonstrates a reference implementation for sending emails with
|
4
|
+
logging and asynchronous support.
|
5
|
+
|
6
|
+
== Resources
|
7
|
+
|
8
|
+
API
|
9
|
+
|
10
|
+
* http://api.pluginaweek.org/has_emails
|
11
|
+
|
12
|
+
Bugs
|
13
|
+
|
14
|
+
* http://pluginaweek.lighthouseapp.com/projects/13272-has_emails
|
15
|
+
|
16
|
+
Development
|
17
|
+
|
18
|
+
* http://github.com/pluginaweek/has_emails
|
19
|
+
|
20
|
+
Source
|
21
|
+
|
22
|
+
* git://github.com/pluginaweek/has_emails.git
|
23
|
+
|
24
|
+
== Description
|
25
|
+
|
26
|
+
Emailing between users and other parts of a system is a fairly common feature
|
27
|
+
in web applications, especially for those that support social networking.
|
28
|
+
Emailing doesn't necessarily need to be between users, but can also act as a
|
29
|
+
way for the web application to send notices and other notifications to users.
|
30
|
+
|
31
|
+
Rails already provides ActionMailer as a way of sending emails. However, the
|
32
|
+
framework does not provide an easy way to persist emails, track their status,
|
33
|
+
and process them asynchronously. Designing and building a framework that
|
34
|
+
supports this can be complex and takes away from the business focus. This
|
35
|
+
plugin can help ease that process by demonstrating a reference implementation
|
36
|
+
of these features.
|
37
|
+
|
38
|
+
== Usage
|
39
|
+
|
40
|
+
=== Creating new emails
|
41
|
+
|
42
|
+
Emails should usually still be created using ActionMailer. However, instead of
|
43
|
+
delivering the emails, you can queue the emails like so:
|
44
|
+
|
45
|
+
Notifier.deliver_signup_notification(david) # sends the email now
|
46
|
+
Notifier.queue_signup_notification(david) # sends the email later (has_emails kicks in)
|
47
|
+
|
48
|
+
In addition to queueing emails, you can build them directly like so:
|
49
|
+
|
50
|
+
email_address = EmailAddress.find(123)
|
51
|
+
email = email_address.emails.build
|
52
|
+
email.to EmailAddress.find(456)
|
53
|
+
email.subject = 'Hey!'
|
54
|
+
email.body = 'Does anyone want to go out tonight?'
|
55
|
+
email.deliver
|
56
|
+
|
57
|
+
=== Replying to emails
|
58
|
+
|
59
|
+
reply = email.reply_to_all
|
60
|
+
reply.body = "I'd love to go out!"
|
61
|
+
reply.deliver
|
62
|
+
|
63
|
+
=== Forwarding emails
|
64
|
+
|
65
|
+
forward = email.forward
|
66
|
+
forward.body = 'Interested?'
|
67
|
+
forward.deliver
|
68
|
+
|
69
|
+
=== Processing email asynchronously
|
70
|
+
|
71
|
+
In addition to delivering emails immediately, you can also *queue* emails so
|
72
|
+
that an external application processes and delivers them (as mentioned above).
|
73
|
+
This is especially useful when you want to asynchronously send e-mails so that
|
74
|
+
it doesn't block the user interface on your web application.
|
75
|
+
|
76
|
+
To process queued emails, you need an external cron job that checks and sends
|
77
|
+
them like so:
|
78
|
+
|
79
|
+
Email.with_state('queued').each do |email|
|
80
|
+
email.deliver
|
81
|
+
end
|
82
|
+
|
83
|
+
== Testing
|
84
|
+
|
85
|
+
Before you can run any tests, the following gem must be installed:
|
86
|
+
* plugin_test_helper[http://github.com/pluginaweek/plugin_test_helper]
|
87
|
+
|
88
|
+
To run against a specific version of Rails:
|
89
|
+
|
90
|
+
rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
|
91
|
+
|
92
|
+
== Dependencies
|
93
|
+
|
94
|
+
* Rails 2.3 or later
|
95
|
+
* has_messages[http://github.com/pluginaweek/has_messages]
|
96
|
+
* state_machine[http://github.com/pluginaweek/state_machine]
|
data/Rakefile
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/contrib/sshpublisher'
|
5
|
+
|
6
|
+
spec = Gem::Specification.new do |s|
|
7
|
+
s.name = 'has_emails'
|
8
|
+
s.version = '0.3.0'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'Demonstrates a reference implementation for sending emails with logging and asynchronous support in ActiveRecord'
|
11
|
+
s.description = s.summary
|
12
|
+
|
13
|
+
s.files = FileList['{app,db,lib,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc) - FileList['test/app_root/{log,log/*,script,script/*}']
|
14
|
+
s.require_path = 'lib'
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.test_files = Dir['test/**/*_test.rb']
|
17
|
+
s.add_dependency 'has_messages', '>= 0.4.0'
|
18
|
+
s.add_dependency 'validates_as_email_address', '>= 0.0.2'
|
19
|
+
|
20
|
+
s.author = 'Aaron Pfeifer'
|
21
|
+
s.email = 'aaron@pluginaweek.org'
|
22
|
+
s.homepage = 'http://www.pluginaweek.org'
|
23
|
+
s.rubyforge_project = 'pluginaweek'
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Default: run all tests.'
|
27
|
+
task :default => :test
|
28
|
+
|
29
|
+
desc "Test the #{spec.name} plugin."
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.test_files = spec.test_files
|
33
|
+
t.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'rcov/rcovtask'
|
38
|
+
namespace :test do
|
39
|
+
desc "Test the #{spec.name} plugin with Rcov."
|
40
|
+
Rcov::RcovTask.new(:rcov) do |t|
|
41
|
+
t.libs << 'lib'
|
42
|
+
t.test_files = spec.test_files
|
43
|
+
t.rcov_opts << '--exclude="^(?!lib/|app/)"'
|
44
|
+
t.verbose = true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
rescue LoadError
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Generate documentation for the #{spec.name} plugin."
|
51
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
52
|
+
rdoc.rdoc_dir = 'rdoc'
|
53
|
+
rdoc.title = spec.name
|
54
|
+
rdoc.template = '../rdoc_template.rb'
|
55
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
56
|
+
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb', 'app/**/*.rb')
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'Generate a gemspec file.'
|
60
|
+
task :gemspec do
|
61
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
62
|
+
f.write spec.to_ruby
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Rake::GemPackageTask.new(spec) do |p|
|
67
|
+
p.gem_spec = spec
|
68
|
+
p.need_tar = true
|
69
|
+
p.need_zip = true
|
70
|
+
end
|
71
|
+
|
72
|
+
desc 'Publish the beta gem.'
|
73
|
+
task :pgem => [:package] do
|
74
|
+
Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'Publish the API documentation.'
|
78
|
+
task :pdoc => [:rdoc] do
|
79
|
+
Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
|
80
|
+
end
|
81
|
+
|
82
|
+
desc 'Publish the API docs and gem'
|
83
|
+
task :publish => [:pgem, :pdoc, :release]
|
84
|
+
|
85
|
+
desc 'Publish the release files to RubyForge.'
|
86
|
+
task :release => [:gem, :package] do
|
87
|
+
require 'rubyforge'
|
88
|
+
|
89
|
+
ruby_forge = RubyForge.new.configure
|
90
|
+
ruby_forge.login
|
91
|
+
|
92
|
+
%w(gem tgz zip).each do |ext|
|
93
|
+
file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
|
94
|
+
puts "Releasing #{File.basename(file)}..."
|
95
|
+
|
96
|
+
ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
|
97
|
+
end
|
98
|
+
end
|
data/app/models/email.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Represents an email which has been sent to one or more recipients. This is
|
2
|
+
# essentially the same as the Message class, but changes how the it is
|
3
|
+
# delivered.
|
4
|
+
class Email < Message
|
5
|
+
state_machine :state do
|
6
|
+
after_transition :on => :deliver, :do => :deliver_email
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
# Actually delivers the email to the recipients using ActionMailer
|
11
|
+
def deliver_email
|
12
|
+
ActionMailer::Base.deliver_email(self)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Represents a valid RFC822 email address. See http://www.w3.org/Protocols/rfc822/
|
2
|
+
# for more information about the entire specification.
|
3
|
+
#
|
4
|
+
# Email addresses are directly associated with emails and, therefore, should be
|
5
|
+
# used for building and delivering new e-mails.
|
6
|
+
#
|
7
|
+
# == Associations
|
8
|
+
#
|
9
|
+
# Email addresses have the following associations defined as a result of using
|
10
|
+
# the +has_emails+ macro:
|
11
|
+
# * +emails+ - Emails that were composed and are visible to the owner. Emails
|
12
|
+
# may have been sent or unsent.
|
13
|
+
# * +received_emails+ - Emails that have been received from others and are
|
14
|
+
# visible. Emails may have been read or unread.
|
15
|
+
# * +unsent_emails+ - Emails that have not yet been delivered
|
16
|
+
# * +sent_emails+ - Emails that have already been delivered
|
17
|
+
class EmailAddress < ActiveRecord::Base
|
18
|
+
has_emails
|
19
|
+
|
20
|
+
validates_presence_of :spec
|
21
|
+
validates_as_email_address :spec
|
22
|
+
validates_uniqueness_of :spec, :scope => 'name'
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# Finds or create an email address based on the given value
|
26
|
+
def find_or_create_by_address(address)
|
27
|
+
name, spec = split_address(address)
|
28
|
+
find_or_create_by_name_and_spec(name, spec)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Splits the given address into a name and spec. For example,
|
32
|
+
#
|
33
|
+
# EmailAddress.split_address("John Smith <john.smith@gmail.com") # => ["John Smith", "john.smith@gmail.com"]
|
34
|
+
# EmailAddress.split_address("john.smith@gmail.com") # => [nil, "john.smith@gmail.com"]
|
35
|
+
def split_address(address)
|
36
|
+
if match = /^(\S.*)\s+<(.*)>$/.match(address)
|
37
|
+
name = match[1]
|
38
|
+
spec = match[2]
|
39
|
+
else
|
40
|
+
spec = address
|
41
|
+
end
|
42
|
+
|
43
|
+
return name, spec
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Sets the value to be used for this email address. This can come in two formats:
|
48
|
+
# * With name - John Doe <john.doe@gmail.com>
|
49
|
+
# * Without name - john.doe@gmail.com
|
50
|
+
def address=(address)
|
51
|
+
self.name, self.spec = self.class.split_address(address)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Generates the value for the email address, including the name associated with
|
55
|
+
# it (if provided). For example,
|
56
|
+
#
|
57
|
+
# e = EmailAddress.new(:name => 'John Doe', :spec => 'john.doe@gmail.com')
|
58
|
+
# e.with_name # => "John Doe <john.doe@gmail.com>"
|
59
|
+
def with_name
|
60
|
+
name.blank? ? spec : "#{name} <#{spec}>"
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateEmailAddresses < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :email_addresses do |t|
|
4
|
+
t.string :spec, :null => false, :limit => 382
|
5
|
+
t.string :name
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
add_index :email_addresses, [:spec, :name], :unique => true
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
drop_table :email_addresses
|
13
|
+
end
|
14
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'has_emails'
|
data/lib/has_emails.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'has_messages'
|
2
|
+
require 'validates_as_email_address'
|
3
|
+
require 'has_emails/extensions/action_mailer'
|
4
|
+
|
5
|
+
# Adds a generic implementation for sending emails
|
6
|
+
module HasEmails
|
7
|
+
module MacroMethods
|
8
|
+
# Creates the following email associations:
|
9
|
+
# * +emails+ - Emails that were composed and are visible to the owner.
|
10
|
+
# Emails may have been sent or unsent.
|
11
|
+
# * +received_emails - Emails that have been received from others and are
|
12
|
+
# visible. Emails may have been read or unread.
|
13
|
+
#
|
14
|
+
# == Creating new emails
|
15
|
+
#
|
16
|
+
# To create a new email, the +emails+ association should be used. For
|
17
|
+
# example:
|
18
|
+
#
|
19
|
+
# address = EmailAddress.find(123)
|
20
|
+
# email = user.emails.build
|
21
|
+
# email.subject = 'Hello'
|
22
|
+
# email.body = 'How are you?'
|
23
|
+
# email.to EmailAddress.find(456)
|
24
|
+
# email.save!
|
25
|
+
# email.deliver!
|
26
|
+
def has_emails
|
27
|
+
has_many :emails,
|
28
|
+
:as => :sender,
|
29
|
+
:class_name => 'Email',
|
30
|
+
:conditions => {:hidden_at => nil},
|
31
|
+
:order => 'messages.created_at ASC'
|
32
|
+
has_many :received_emails,
|
33
|
+
:as => :receiver,
|
34
|
+
:class_name => 'MessageRecipient',
|
35
|
+
:include => :message,
|
36
|
+
:conditions => ['message_recipients.hidden_at IS NULL AND messages.state = ?', 'sent'],
|
37
|
+
:order => 'messages.created_at ASC'
|
38
|
+
|
39
|
+
include HasEmails::InstanceMethods
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module InstanceMethods
|
44
|
+
# Composed emails that have not yet been sent. These consists of all
|
45
|
+
# emails that are currently in the "unsent" state.
|
46
|
+
def unsent_emails
|
47
|
+
emails.with_state(:unsent)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Composed emails that have already been sent. These consist of all emails
|
51
|
+
# that are currently in the "queued" or "sent states.
|
52
|
+
def sent_emails
|
53
|
+
emails.with_states(:queued, :sent)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
ActiveRecord::Base.class_eval do
|
59
|
+
extend HasEmails::MacroMethods
|
60
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module HasEmails
|
2
|
+
module Extensions #:nodoc:
|
3
|
+
# Adds support for queueing emails so that they can be procssed in the
|
4
|
+
# background. Emails are stored in the database using the Email ActiveRecord
|
5
|
+
# model.
|
6
|
+
#
|
7
|
+
# == Queueing mail
|
8
|
+
#
|
9
|
+
# Once a mailer action and template are defined, you can queue your message
|
10
|
+
# for background processing like so:
|
11
|
+
#
|
12
|
+
# Notifier.queue_signup_notification(john_smith) # Queues the email
|
13
|
+
#
|
14
|
+
# If you were to deliver the mail immediately, the normal process would be
|
15
|
+
# used like so:
|
16
|
+
#
|
17
|
+
# Notifier.deliver_signup_notification(john_smith) # Delivers the email
|
18
|
+
module ActionMailer
|
19
|
+
def self.included(base) #:nodoc:
|
20
|
+
base.class_eval do
|
21
|
+
@@default_subject_prefix = "[#{File.basename(File.expand_path(Rails.root)).camelize}] "
|
22
|
+
cattr_accessor :default_subject_prefix
|
23
|
+
|
24
|
+
# Specify the prefix to use for the subject. This defaults to the
|
25
|
+
# +default_subject_prefix+ specified for ActionMailer::Base.
|
26
|
+
adv_attr_accessor :subject_prefix
|
27
|
+
|
28
|
+
include HasEmails::Extensions::ActionMailer::InstanceMethods
|
29
|
+
extend HasEmails::Extensions::ActionMailer::ClassMethods
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def self.extended(base) #:nodoc:
|
35
|
+
class << base
|
36
|
+
alias_method_chain :method_missing, :has_emails
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Handles calls to queue_*
|
41
|
+
def method_missing_with_has_emails(method_symbol, *parameters)
|
42
|
+
case method_symbol.id2name
|
43
|
+
when /^queue_([_a-z]\w*)/
|
44
|
+
# Queues the mail so that it's processed in the background
|
45
|
+
new($1, *parameters).queue
|
46
|
+
else
|
47
|
+
# Handle the mail delivery as normal
|
48
|
+
method_missing_without_has_emails(method_symbol, *parameters)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module InstanceMethods
|
54
|
+
def self.included(base) #:nodoc:
|
55
|
+
base.class_eval do
|
56
|
+
alias_method_chain :initialize_defaults, :subject_prefix
|
57
|
+
alias_method_chain :subject, :prefix
|
58
|
+
alias_method :subject=, :subject_with_prefix
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sets or gets the subject of the email. All subjects are prefixed with a
|
63
|
+
# value indicating the application it is coming from.
|
64
|
+
def subject_with_prefix(*parameters)
|
65
|
+
if parameters.empty?
|
66
|
+
subject_without_prefix
|
67
|
+
else
|
68
|
+
subject_without_prefix(subject_prefix + subject_without_prefix(*parameters))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets the default subject prefix
|
73
|
+
def initialize_defaults_with_subject_prefix(method_name) #:nodoc
|
74
|
+
initialize_defaults_without_subject_prefix(method_name)
|
75
|
+
@subject_prefix ||= ::ActionMailer::Base.default_subject_prefix.dup
|
76
|
+
end
|
77
|
+
|
78
|
+
# Delivers an email based on the content in the specified email
|
79
|
+
def email(email)
|
80
|
+
@from = email.sender.with_name
|
81
|
+
@recipients = email.to.map(&:with_name)
|
82
|
+
@cc = email.cc.map(&:with_name)
|
83
|
+
@bcc = email.bcc.map(&:with_name)
|
84
|
+
@subject = email.subject || ''
|
85
|
+
@body = email.body || ''
|
86
|
+
@sent_on = email.updated_at
|
87
|
+
end
|
88
|
+
|
89
|
+
# Queues the current e-mail that has been constructed
|
90
|
+
def queue
|
91
|
+
Email.transaction do
|
92
|
+
# Create the main email
|
93
|
+
email = EmailAddress.find_or_create_by_address(from).emails.build(
|
94
|
+
:subject => subject,
|
95
|
+
:body => body,
|
96
|
+
:to => email_addresses_for(:recipients),
|
97
|
+
:cc => email_addresses_for(:cc),
|
98
|
+
:bcc => email_addresses_for(:bcc)
|
99
|
+
)
|
100
|
+
email.queue!
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
# Finds or creates all of the email addresses for the given type of
|
106
|
+
# recipient (can be :recipients, :cc, or :bcc)
|
107
|
+
def email_addresses_for(kind)
|
108
|
+
[send(kind)].flatten.collect {|address| EmailAddress.find_or_create_by_address(address)}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
ActionMailer::Base.class_eval do
|
116
|
+
include HasEmails::Extensions::ActionMailer
|
117
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'config/boot'
|
2
|
+
|
3
|
+
Rails::Initializer.run do |config|
|
4
|
+
config.plugin_paths << '..'
|
5
|
+
config.plugins = %w(plugin_tracker state_machine has_messages validates_as_email_address has_emails)
|
6
|
+
config.cache_classes = false
|
7
|
+
config.whiny_nils = true
|
8
|
+
config.action_mailer.delivery_method = :test
|
9
|
+
config.action_controller.session = {:key => 'rails_session', :secret => 'd229e4d22437432705ab3985d4d246'}
|
10
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class MigrateHasMessagesToVersion2 < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
ActiveRecord::Migrator.new(:up, "#{directory}/db/migrate", 0).migrations.each do |migration|
|
4
|
+
migration.migrate(:up)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
ActiveRecord::Migrator.new(:up, "#{directory}/db/migrate", 0).migrations.each do |migration|
|
10
|
+
migration.migrate(:down)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def self.directory
|
16
|
+
Rails.plugins.find {|plugin| plugin.name == 'has_messages'}.directory
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class MigrateHasEmailsToVersion1 < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
ActiveRecord::Migrator.new(:up, "#{Rails.root}/../../db/migrate", 0).migrations.each do |migration|
|
4
|
+
migration.migrate(:up)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
ActiveRecord::Migrator.new(:up, "#{Rails.root}/../../db/migrate", 0).migrations.each do |migration|
|
10
|
+
migration.migrate(:down)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/test/factory.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Factory
|
2
|
+
# Build actions for the model
|
3
|
+
def self.build(model, &block)
|
4
|
+
name = model.to_s.underscore
|
5
|
+
|
6
|
+
define_method("#{name}_attributes", block)
|
7
|
+
define_method("valid_#{name}_attributes") {|*args| valid_attributes_for(model, *args)}
|
8
|
+
define_method("new_#{name}") {|*args| new_record(model, *args)}
|
9
|
+
define_method("create_#{name}") {|*args| create_record(model, *args)}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get valid attributes for the model
|
13
|
+
def valid_attributes_for(model, attributes = {})
|
14
|
+
name = model.to_s.underscore
|
15
|
+
send("#{name}_attributes", attributes)
|
16
|
+
attributes.stringify_keys!
|
17
|
+
attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
# Build an unsaved record
|
21
|
+
def new_record(model, *args)
|
22
|
+
attributes = valid_attributes_for(model, *args)
|
23
|
+
record = model.new(attributes)
|
24
|
+
attributes.each {|attr, value| record.send("#{attr}=", value) if model.accessible_attributes && !model.accessible_attributes.include?(attr) || model.protected_attributes && model.protected_attributes.include?(attr)}
|
25
|
+
record
|
26
|
+
end
|
27
|
+
|
28
|
+
# Build and save/reload a record
|
29
|
+
def create_record(model, *args)
|
30
|
+
record = new_record(model, *args)
|
31
|
+
record.save!
|
32
|
+
record.reload
|
33
|
+
record
|
34
|
+
end
|
35
|
+
|
36
|
+
build Email do |attributes|
|
37
|
+
attributes[:sender] = create_user unless attributes.include?(:sender)
|
38
|
+
attributes.reverse_merge!(
|
39
|
+
:subject => 'New features',
|
40
|
+
:body => 'Lots of new things to talk about... come to the meeting tonight to find out!'
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
build EmailAddress do |attributes|
|
45
|
+
attributes.reverse_merge!(
|
46
|
+
:name => 'John Smith',
|
47
|
+
:spec => 'john.smith@gmail.com'
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
build MessageRecipient do |attributes|
|
52
|
+
attributes[:message] = create_message unless attributes.include?(:message)
|
53
|
+
attributes[:receiver] = create_user(:login => 'me') unless attributes.include?(:receiver)
|
54
|
+
attributes.reverse_merge!(
|
55
|
+
:kind => 'to'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class EmailAddressByDefaultFunctionalTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
@email_address = create_email_address
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_not_have_any_emails
|
9
|
+
assert @email_address.emails.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_not_have_any_unsent_emails
|
13
|
+
assert @email_address.unsent_emails.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_should_not_have_any_sent_emails
|
17
|
+
assert @email_address.sent_emails.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_not_have_any_received_emails
|
21
|
+
assert @email_address.received_emails.empty?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class EmailAddressFunctionalTest < ActiveSupport::TestCase
|
26
|
+
def setup
|
27
|
+
@email_address = create_email_address
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_be_able_to_create_new_emails
|
31
|
+
email = @email_address.emails.build
|
32
|
+
assert_instance_of Email, email
|
33
|
+
assert_equal @email_address, email.sender
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_should_be_able_to_send_new_emails
|
37
|
+
email = @email_address.emails.build
|
38
|
+
email.to create_email_address(:spec => 'jane.smith@gmail.com')
|
39
|
+
assert email.deliver
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class EmailAddressWithUnsentEmails < ActiveSupport::TestCase
|
44
|
+
def setup
|
45
|
+
@email_address = create_email_address
|
46
|
+
@sent_email = create_email(:sender => @email_address, :to => create_email_address(:spec => 'jane.smith@gmail.com'))
|
47
|
+
@sent_email.deliver
|
48
|
+
@first_draft = create_email(:sender => @email_address)
|
49
|
+
@second_draft = create_email(:sender => @email_address)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_should_have_unsent_emails
|
53
|
+
assert_equal [@first_draft, @second_draft], @email_address.unsent_emails
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_should_include_unsent_emails_in_emails
|
57
|
+
assert_equal [@sent_email, @first_draft, @second_draft], @email_address.emails
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class EmailAddressWithSentEmails < ActiveSupport::TestCase
|
62
|
+
def setup
|
63
|
+
@email_address = create_email_address
|
64
|
+
@to = create_email_address(:spec => 'jane.smith@gmail.com')
|
65
|
+
@draft = create_email(:sender => @email_address)
|
66
|
+
|
67
|
+
@first_sent_email = create_email(:sender => @email_address, :to => @to)
|
68
|
+
@first_sent_email.deliver
|
69
|
+
|
70
|
+
@second_sent_email = create_email(:sender => @email_address, :to => @to)
|
71
|
+
@second_sent_email.deliver
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_should_have_sent_emails
|
75
|
+
assert_equal [@first_sent_email, @second_sent_email], @email_address.sent_emails
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_should_include_sent_emails_in_emails
|
79
|
+
assert_equal [@draft, @first_sent_email, @second_sent_email], @email_address.emails
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class EmailAddressWithReceivedEmails < ActiveSupport::TestCase
|
84
|
+
def setup
|
85
|
+
@sender = create_email_address
|
86
|
+
@email_address = create_email_address(:spec => 'jane.smith@gmail.com')
|
87
|
+
|
88
|
+
@unsent_email = create_email(:sender => @sender, :to => @email_address)
|
89
|
+
|
90
|
+
@first_sent_email = create_email(:sender => @sender, :to => @email_address)
|
91
|
+
@first_sent_email.deliver
|
92
|
+
|
93
|
+
@second_sent_email = create_email(:sender => @sender, :to => @email_address)
|
94
|
+
@second_sent_email.deliver
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_should_have_received_emails
|
98
|
+
assert_equal [@first_sent_email, @second_sent_email], @email_address.received_emails.map(&:message)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class EmailAddressWithHiddenEmailsTest < ActiveSupport::TestCase
|
103
|
+
def setup
|
104
|
+
@email_address = create_email_address
|
105
|
+
@friend = create_email_address(:spec => 'jane.smith@gmail.com')
|
106
|
+
|
107
|
+
hidden_unsent_email = create_email(:sender => @email_address)
|
108
|
+
hidden_unsent_email.hide
|
109
|
+
@unsent_email = create_email(:sender => @email_address)
|
110
|
+
|
111
|
+
hidden_sent_email = create_email(:sender => @email_address, :to => @friend)
|
112
|
+
hidden_sent_email.deliver
|
113
|
+
hidden_sent_email.hide
|
114
|
+
@sent_email = create_email(:sender => @email_address, :to => @friend)
|
115
|
+
@sent_email.deliver
|
116
|
+
|
117
|
+
hidden_received_email = create_email(:sender => @friend, :to => @email_address)
|
118
|
+
hidden_received_email.deliver
|
119
|
+
hidden_received_email.recipients.first.hide
|
120
|
+
@received_email = create_email(:sender => @friend, :to => @email_address)
|
121
|
+
@received_email.deliver
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_should_not_include_hidden_emails_in_emails
|
125
|
+
assert_equal [@unsent_email, @sent_email], @email_address.emails
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_should_not_include_hidden_emails_in_unsent_emails
|
129
|
+
assert_equal [@unsent_email], @email_address.unsent_emails
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_should_not_include_hidden_emails_in_sent_emails
|
133
|
+
assert_equal [@sent_email], @email_address.sent_emails
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_should_not_include_hidden_emails_in_received_emails
|
137
|
+
assert_equal [@received_email], @email_address.received_emails.map(&:message)
|
138
|
+
end
|
139
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Load the plugin testing framework
|
2
|
+
$:.unshift("#{File.dirname(__FILE__)}/../../plugin_test_helper/lib")
|
3
|
+
require 'rubygems'
|
4
|
+
require 'plugin_test_helper'
|
5
|
+
|
6
|
+
# Run the migrations
|
7
|
+
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
8
|
+
|
9
|
+
# Mixin the factory helper
|
10
|
+
require File.expand_path("#{File.dirname(__FILE__)}/factory")
|
11
|
+
Test::Unit::TestCase.class_eval do
|
12
|
+
include Factory
|
13
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class TestMailer < ActionMailer::Base
|
4
|
+
def signed_up(recipient)
|
5
|
+
subject 'Thanks for signing up'
|
6
|
+
from 'MyWebApp <welcome@mywebapp.com>'
|
7
|
+
recipients recipient
|
8
|
+
cc 'Nobody <nobody@mywebapp.com>'
|
9
|
+
bcc 'root@mywebapp.com'
|
10
|
+
body 'Congratulations!'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestMailerTest < ActionMailer::TestCase
|
15
|
+
def test_should_use_camelized_application_name_for_default_subject_prefix
|
16
|
+
assert_equal '[AppRoot] ', ActionMailer::Base.default_subject_prefix
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_queue_email
|
20
|
+
assert_nothing_raised {TestMailer.queue_signed_up('john.smith@gmail.com')}
|
21
|
+
assert_equal 1, Email.count
|
22
|
+
|
23
|
+
email = Email.find(1)
|
24
|
+
assert_equal '[AppRoot] Thanks for signing up', email.subject
|
25
|
+
assert_equal 'Congratulations!', email.body
|
26
|
+
assert_equal 'MyWebApp <welcome@mywebapp.com>', email.sender.with_name
|
27
|
+
assert_equal ['john.smith@gmail.com'], email.to.map(&:with_name)
|
28
|
+
assert_equal ['Nobody <nobody@mywebapp.com>'], email.cc.map(&:with_name)
|
29
|
+
assert_equal ['root@mywebapp.com'], email.bcc.map(&:with_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_deliver_email
|
33
|
+
email = create_email(
|
34
|
+
:subject => 'Hello',
|
35
|
+
:body => 'How are you?',
|
36
|
+
:sender => create_email_address(:name => 'MyWebApp', :spec => 'welcome@mywebapp.com'),
|
37
|
+
:to => create_email_address(:spec => 'john.smith@gmail.com'),
|
38
|
+
:cc => create_email_address(:name => 'Nobody', :spec => 'nobody@mywebapp.com'),
|
39
|
+
:bcc => create_email_address(:spec => 'root@mywebapp.com')
|
40
|
+
)
|
41
|
+
|
42
|
+
assert_nothing_raised {ActionMailer::Base.deliver_email(email)}
|
43
|
+
assert_equal 1, ActionMailer::Base.deliveries.size
|
44
|
+
|
45
|
+
delivery = ActionMailer::Base.deliveries.first
|
46
|
+
assert_equal 'Hello', delivery.subject
|
47
|
+
assert_equal 'How are you?', delivery.body
|
48
|
+
assert_equal ['welcome@mywebapp.com'], delivery.from
|
49
|
+
assert_equal ['john.smith@gmail.com'], delivery.to
|
50
|
+
assert_equal ['nobody@mywebapp.com'], delivery.cc
|
51
|
+
assert_equal ['root@mywebapp.com'], delivery.bcc
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class EmailAddressByDefaultTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
@email_address = EmailAddress.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_not_have_a_name
|
9
|
+
assert @email_address.name.blank?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_not_have_a_spec
|
13
|
+
assert @email_address.name.blank?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class EmailAddressTest < ActiveSupport::TestCase
|
18
|
+
def test_should_be_valid_with_a_set_of_valid_attributes
|
19
|
+
email_address = new_email_address
|
20
|
+
assert email_address.valid?
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_should_require_a_spec
|
24
|
+
email_address = new_email_address(:spec => nil)
|
25
|
+
assert !email_address.valid?
|
26
|
+
assert email_address.errors.invalid?(:spec)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_require_a_properly_formatted_email
|
30
|
+
email_address = new_email_address(:spec => '!@@!@@!')
|
31
|
+
assert !email_address.valid?
|
32
|
+
assert email_address.errors.invalid?(:spec)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_not_allow_emails_less_than_3_characters
|
36
|
+
email_address = new_email_address(:spec => 'aa')
|
37
|
+
assert !email_address.valid?
|
38
|
+
assert email_address.errors.invalid?(:spec)
|
39
|
+
|
40
|
+
email_address.spec = 'a@a'
|
41
|
+
assert email_address.valid?
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_not_allow_emails_longer_than_320_characters
|
45
|
+
email_address = new_email_address(:spec => 'a' * 314 + '@a.com')
|
46
|
+
assert email_address.valid?
|
47
|
+
|
48
|
+
email_address.spec += 'a'
|
49
|
+
assert !email_address.valid?
|
50
|
+
assert email_address.errors.invalid?(:spec)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_require_a_unique_spec_scoped_by_name
|
54
|
+
email_address = create_email_address(:spec => 'john.smith@gmail.com', :name => 'John Smith')
|
55
|
+
|
56
|
+
second_email_address = new_email_address(:spec => 'john.smith@gmail.com', :name => 'John Smith II')
|
57
|
+
assert second_email_address.valid?
|
58
|
+
|
59
|
+
second_email_address = new_email_address(:spec => 'john.smith@gmail.com', :name => 'John Smith')
|
60
|
+
assert !second_email_address.valid?
|
61
|
+
assert second_email_address.errors.invalid?(:spec)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_should_not_require_a_name
|
65
|
+
email_address = new_email_address(:name => nil)
|
66
|
+
assert email_address.valid?
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_should_protect_attributes_from_mass_assignment
|
70
|
+
email_address = EmailAddress.new(
|
71
|
+
:id => 1,
|
72
|
+
:name => 'John Smith',
|
73
|
+
:spec => 'john.smith@gmail.com'
|
74
|
+
)
|
75
|
+
|
76
|
+
assert_nil email_address.id
|
77
|
+
assert_equal 'John Smith', email_address.name
|
78
|
+
assert_equal 'john.smith@gmail.com', email_address.spec
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class EmailAddressFromAddressTest < ActiveSupport::TestCase
|
83
|
+
def setup
|
84
|
+
@email_address = EmailAddress.new(:address => 'John Smith <john.smith@gmail.com>')
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_should_be_valid
|
88
|
+
assert @email_address.valid?
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_should_find_a_name
|
92
|
+
assert_equal 'John Smith', @email_address.name
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_should_find_a_spec
|
96
|
+
assert_equal 'john.smith@gmail.com', @email_address.spec
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class EmailAddressFromAddressWithoutNameTest < ActiveSupport::TestCase
|
101
|
+
def setup
|
102
|
+
@email_address = EmailAddress.new(:address => 'john.smith@gmail.com')
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_should_be_valid
|
106
|
+
assert @email_address.valid?
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_should_not_find_a_name
|
110
|
+
assert @email_address.name.blank?
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_should_find_a_spec
|
114
|
+
assert_equal 'john.smith@gmail.com', @email_address.spec
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class EmailAddressAfterBeingCreatedTest < ActiveSupport::TestCase
|
119
|
+
def setup
|
120
|
+
@email_address = create_email_address(:name => 'John Smith', :spec => 'john.smith@gmail.com')
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_should_record_when_it_was_created
|
124
|
+
assert_not_nil @email_address.created_at
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_should_record_when_it_was_updated
|
128
|
+
assert_not_nil @email_address.updated_at
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_should_generate_an_address_with_the_name
|
132
|
+
assert_equal 'John Smith <john.smith@gmail.com>', @email_address.with_name
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class EmailAddressAsAClassTest < ActiveSupport::TestCase
|
137
|
+
def test_should_be_able_to_split_address_containing_name
|
138
|
+
name, spec = EmailAddress.split_address('John Smith <john.smith@gmail.com>')
|
139
|
+
assert_equal 'John Smith', name
|
140
|
+
assert_equal 'john.smith@gmail.com', spec
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_should_be_able_to_split_address_not_containing_name
|
144
|
+
name, spec = EmailAddress.split_address('john.smith@gmail.com')
|
145
|
+
assert_nil name
|
146
|
+
assert_equal 'john.smith@gmail.com', spec
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_should_be_able_to_find_an_existing_email_by_address
|
150
|
+
email_address = create_email_address(:address => 'John Smith <john.smith@gmail.com>')
|
151
|
+
assert_equal email_address, EmailAddress.find_or_create_by_address('John Smith <john.smith@gmail.com>')
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_should_be_able_to_create_from_a_new_address
|
155
|
+
email_address = EmailAddress.find_or_create_by_address('John Smith <john.smith@gmail.com>')
|
156
|
+
assert !email_address.new_record?
|
157
|
+
assert_equal 'John Smith', email_address.name
|
158
|
+
assert_equal 'john.smith@gmail.com', email_address.spec
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class EmailAfterBeingDeliveredTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
ActionMailer::Base.deliveries = []
|
6
|
+
|
7
|
+
@email = new_email(
|
8
|
+
:subject => 'Hello',
|
9
|
+
:body => 'How are you?',
|
10
|
+
:sender => create_email_address(:spec => 'webmaster@localhost'),
|
11
|
+
:to => create_email_address(:spec => 'partners@localhost'),
|
12
|
+
:cc => create_email_address(:spec => 'support@localhost'),
|
13
|
+
:bcc => create_email_address(:spec => 'feedback@localhost')
|
14
|
+
)
|
15
|
+
assert @email.deliver
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_send_mail
|
19
|
+
assert ActionMailer::Base.deliveries.any?
|
20
|
+
|
21
|
+
delivery = ActionMailer::Base.deliveries.first
|
22
|
+
assert_equal 'Hello', delivery.subject
|
23
|
+
assert_equal 'How are you?', delivery.body
|
24
|
+
assert_equal ['webmaster@localhost'], delivery.from
|
25
|
+
assert_equal ['partners@localhost'], delivery.to
|
26
|
+
assert_equal ['support@localhost'], delivery.cc
|
27
|
+
assert_equal ['feedback@localhost'], delivery.bcc
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pluginaweek-has_emails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Pfeifer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-08 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: has_messages
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: validates_as_email_address
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.2
|
34
|
+
version:
|
35
|
+
description: Demonstrates a reference implementation for sending emails with logging and asynchronous support in ActiveRecord
|
36
|
+
email: aaron@pluginaweek.org
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- app/models
|
45
|
+
- app/models/email_address.rb
|
46
|
+
- app/models/email.rb
|
47
|
+
- db/migrate
|
48
|
+
- db/migrate/001_create_email_addresses.rb
|
49
|
+
- lib/has_emails.rb
|
50
|
+
- lib/has_emails
|
51
|
+
- lib/has_emails/extensions
|
52
|
+
- lib/has_emails/extensions/action_mailer.rb
|
53
|
+
- test/unit
|
54
|
+
- test/unit/email_address_test.rb
|
55
|
+
- test/unit/email_test.rb
|
56
|
+
- test/unit/action_mailer_test.rb
|
57
|
+
- test/factory.rb
|
58
|
+
- test/app_root
|
59
|
+
- test/app_root/vendor
|
60
|
+
- test/app_root/vendor/plugins
|
61
|
+
- test/app_root/vendor/plugins/plugin_tracker
|
62
|
+
- test/app_root/vendor/plugins/plugin_tracker/init.rb
|
63
|
+
- test/app_root/db
|
64
|
+
- test/app_root/db/migrate
|
65
|
+
- test/app_root/db/migrate/002_migrate_has_emails_to_version_1.rb
|
66
|
+
- test/app_root/db/migrate/001_migrate_has_messages_to_version_2.rb
|
67
|
+
- test/app_root/config
|
68
|
+
- test/app_root/config/environment.rb
|
69
|
+
- test/test_helper.rb
|
70
|
+
- test/functional
|
71
|
+
- test/functional/has_emails_test.rb
|
72
|
+
- CHANGELOG.rdoc
|
73
|
+
- init.rb
|
74
|
+
- LICENSE
|
75
|
+
- Rakefile
|
76
|
+
- README.rdoc
|
77
|
+
has_rdoc: true
|
78
|
+
homepage: http://www.pluginaweek.org
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
version:
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
version:
|
96
|
+
requirements: []
|
97
|
+
|
98
|
+
rubyforge_project: pluginaweek
|
99
|
+
rubygems_version: 1.2.0
|
100
|
+
signing_key:
|
101
|
+
specification_version: 2
|
102
|
+
summary: Demonstrates a reference implementation for sending emails with logging and asynchronous support in ActiveRecord
|
103
|
+
test_files:
|
104
|
+
- test/unit/email_address_test.rb
|
105
|
+
- test/unit/email_test.rb
|
106
|
+
- test/unit/action_mailer_test.rb
|
107
|
+
- test/functional/has_emails_test.rb
|