pluginaweek-has_emails 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|