markbates-blabber_mouth 0.1.0.20090714164111

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 markbates
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,29 @@
1
+ This gem provides a simple API for creating emails within a Mack application.
2
+
3
+ A simple BlabberMouth model would look like this:
4
+
5
+ class WelcomeEmail
6
+ include BlabberMouth
7
+ end
8
+
9
+ To use this in your application you would do something like the following:
10
+
11
+ mail = WelcomeEmail.new
12
+ mail.to = "foo@example.com"
13
+ mail.from = "me@example.com"
14
+ mail.subject = "Hello"
15
+ mail.body(:plain, "This is my plain text body")
16
+ mail.body(:html, "This is my <b>HTML</b> body")
17
+ mail.attach(BlabberMouth::Attachment.new("/path/to/my/image_file.png"))
18
+ mail.attach(BlabberMouth::Attachment.new("/path/to/my/pdf_file.pdf"))
19
+ mail.deliver
20
+
21
+ This gem currently has an adapter for TMail, but it can support any mailing
22
+ framework under the covers with the creation of a simple adapter class.
23
+
24
+ Currently implemented delivery handlers are: SMTP (default), sendmail, and test.
25
+
26
+ == Testing
27
+
28
+ When testing you can get access to delivered emails with the delivered_notifiers
29
+ method. After each tests these emails will be flushed our of the test handler.
@@ -0,0 +1,28 @@
1
+ require 'configatron'
2
+ require 'genosaurus'
3
+ require 'validatable'
4
+ require 'tmail'
5
+ require 'xmpp4r'
6
+ require 'xmpp4r-simple'
7
+ require 'activesupport'
8
+
9
+ fl = File.join(File.dirname(__FILE__), "blabber_mouth")
10
+
11
+ require File.join(fl, "settings")
12
+ require File.join(fl, "errors")
13
+ require File.join(fl, "attachment")
14
+ require File.join(fl, "notifier_generator", "notifier_generator")
15
+
16
+ [:utils, :delivery_handlers, :adapters, :rendering].each do |dir|
17
+ Dir.glob(File.join(fl, dir.to_s, "**/*.rb")).each do |h|
18
+ require h
19
+ end
20
+ end
21
+
22
+ require File.join(fl, "blabber_mouth")
23
+
24
+ require File.join(fl, "validations")
25
+
26
+ require File.join(fl, "testing")
27
+
28
+ require File.join(fl, "loader")
@@ -0,0 +1,30 @@
1
+ module BlabberMouth
2
+ module Adapters # :nodoc:
3
+ # All mail adapters need to extend this class.
4
+ class Base
5
+
6
+ # The origina BlabberMouth object passed in.
7
+ attr_accessor :bm_notifier
8
+
9
+ def initialize(mail) # :nodoc:
10
+ self.bm_notifier = mail
11
+ end
12
+
13
+ # The transformed (ie, converted, object)
14
+ def transformed(*args)
15
+ raise NoMethodError.new('transformed')
16
+ end
17
+
18
+ # Convert the BlabberMouth object to the adapted object.
19
+ def convert(*args)
20
+ raise NoMethodError.new('convert')
21
+ end
22
+
23
+ # The RAW encoded String ready for delivery via SMTP, Sendmail, etc...
24
+ def deliverable(*args)
25
+ raise NoMethodError.new('deliverable')
26
+ end
27
+
28
+ end # Base
29
+ end # Adapters
30
+ end # BlabberMouth
@@ -0,0 +1,77 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+ require 'base64'
3
+
4
+ module BlabberMouth
5
+ module Adapters # :nodoc:
6
+ # Converts a BlabberMouth object into a TMail object.
7
+ class Tmail < BlabberMouth::Adapters::Base
8
+
9
+ # Returns the underlying TMail object.
10
+ # Raises BlabberMouth::Errors::UnconvertedNotifier if the convert method hasn't
11
+ # been called first.
12
+ def transformed
13
+ raise BlabberMouth::Errors::UnconvertedNotifier.new if @tmail.nil?
14
+ @tmail
15
+ end
16
+
17
+ # Returns the ready to be delivered encoded String
18
+ def deliverable
19
+ transformed.encoded
20
+ end
21
+
22
+ # Converts the BlabberMouth object to a TMail object.
23
+ def convert
24
+ @tmail = TMail::Mail.new
25
+ @tmail.to = bm_notifier.to
26
+ @tmail.cc = bm_notifier.cc
27
+ @tmail.bcc = bm_notifier.bcc
28
+ @tmail.reply_to = bm_notifier.reply_to
29
+ @tmail.from = bm_notifier.from
30
+ @tmail.subject = bm_notifier.subject
31
+ @tmail.date = bm_notifier.date_sent
32
+ @tmail.mime_version = bm_notifier.mime_version
33
+
34
+ # set text and html bodies
35
+ main_body = TMail::Mail.new
36
+ unless bm_notifier.body(:plain).blank?
37
+ text = TMail::Mail.new
38
+ text.content_type = "text/plain"
39
+ text.body = bm_notifier.body(:plain)
40
+ main_body.parts << text
41
+ end
42
+ unless bm_notifier.body(:html).blank?
43
+ html = TMail::Mail.new
44
+ html.content_type = "text/html"
45
+ html.body = bm_notifier.body(:html)
46
+ main_body.parts << html
47
+ end
48
+
49
+ unless main_body.parts.empty?
50
+ main_body.content_type = "multipart/alternative"
51
+ if bm_notifier.attachments.any? # there's an attachment
52
+ @tmail.parts << main_body
53
+ else
54
+ if main_body.parts.size == 1
55
+ @tmail.body = main_body.parts.first.body
56
+ else
57
+ @tmail.parts << main_body
58
+ end
59
+ end
60
+ end
61
+
62
+ # set attachments, if any.
63
+ bm_notifier.attachments.each do |at|
64
+ attachment = TMail::Mail.new
65
+ attachment.body = Base64.encode64(at.body)
66
+ attachment.transfer_encoding = "Base64"
67
+ attachment.content_type = "application/octet-stream"
68
+ attachment['Content-Disposition'] = "attachment; filename=#{at.file_name}"
69
+ @tmail.parts << attachment
70
+ end
71
+
72
+ @tmail.content_type = bm_notifier.content_type
73
+ end
74
+
75
+ end # Tmail
76
+ end # Adapters
77
+ end # BlabberMouth
@@ -0,0 +1,59 @@
1
+ module BlabberMouth
2
+ module Adapters # :nodoc:
3
+
4
+ class XmppMsgContainer
5
+ attr_accessor :messages
6
+ attr_accessor :recipients
7
+ def initialize
8
+ self.messages = []
9
+ self.recipients = []
10
+ end
11
+
12
+ def find_message_by_recipient(rcpt)
13
+ self.messages.find { |x| x.to.to_s == rcpt.to_s }
14
+ end
15
+
16
+ end
17
+
18
+ # All mail adapters need to extend this class.
19
+ class Xmpp < BlabberMouth::Adapters::Base
20
+ include Jabber
21
+
22
+ # The transformed (ie, converted, object)
23
+ def transformed
24
+ raise BlabberMouth::Errors::UnconvertedNotifier.new if @xmpp_msg.nil?
25
+ return @xmpp_container
26
+ end
27
+
28
+ # Convert the BlabberMouth object to the adapted object.
29
+ def convert
30
+ settings = configatron.blabber_mouth.xmpp_settings
31
+ arr = [bm_notifier.to].flatten
32
+ @xmpp_container = XmppMsgContainer.new
33
+ @xmpp_container.recipients = arr
34
+
35
+ arr.each do |rcpt|
36
+ xmpp_msg = Message::new
37
+ xmpp_msg.set_type(:normal)
38
+ xmpp_msg.set_to(rcpt)
39
+ xmpp_msg.set_from(bm_notifier.from)
40
+ xmpp_msg.set_subject(bm_notifier.subject)
41
+ xmpp_msg.set_type(settings.message_type)
42
+ unless bm_notifier.body(:plain).blank?
43
+ xmpp_msg.set_body(bm_notifier.body(:plain))
44
+ end
45
+
46
+ @xmpp_container.messages << xmpp_msg
47
+ end
48
+
49
+ return @xmpp_container
50
+ end
51
+
52
+ # The RAW encoded String ready for delivery via SMTP, Sendmail, etc...
53
+ def deliverable
54
+ return @xmpp_container
55
+ end
56
+
57
+ end # Base
58
+ end # Adapters
59
+ end # BlabberMouth
@@ -0,0 +1,29 @@
1
+ module BlabberMouth
2
+ # Creates an attachment for a BlabberMouth object.
3
+ class Attachment
4
+
5
+ # Returns a String representing the body of the attachment. This String is NOT encoded in anyway!
6
+ attr_accessor :body
7
+ # Returns the name of the attached file.
8
+ attr_accessor :file_name
9
+
10
+ def initialize(body = nil)
11
+ unless body.nil?
12
+ self.add_file(body) if body.is_a?(String)
13
+ self.add_io(body) if body.is_a?(IO)
14
+ end
15
+ end
16
+
17
+ # Takes an IO object and sets the body. You'll need to explicity set the file_name afterwards.
18
+ def add_io(io)
19
+ self.body = io.read
20
+ end
21
+
22
+ # Takes a path to a file, reads it in, and sets the file_name based on the path.
23
+ def add_file(file)
24
+ self.file_name = File.basename(file)
25
+ self.body = File.read(file)
26
+ end
27
+
28
+ end # Attachment
29
+ end # BlabberMouth
@@ -0,0 +1,181 @@
1
+ # The heart and soul of the mack-notifier package.
2
+ module BlabberMouth
3
+
4
+ attr_accessor :to
5
+ attr_accessor :cc
6
+ attr_accessor :bcc
7
+ attr_accessor :from
8
+ attr_accessor :reply_to
9
+ attr_accessor :subject
10
+ attr_accessor :date_sent
11
+ attr_accessor :mime_version
12
+ attr_accessor :content_type
13
+
14
+ # A helper method that takes a Hash and will populate the notification with the key/value pairs of that Hash.
15
+ # Use body_* to set a body part.
16
+ def build(options = {})
17
+ options.each do |k,v|
18
+ k = k.to_s
19
+ unless k.match(/^body_/)
20
+ self.send("#{k}=", v)
21
+ else
22
+ k.gsub!("body_", "")
23
+ self.body(k, v)
24
+ end
25
+ end
26
+ end
27
+
28
+ # If called with two parameters it will set the value of the body type to the second parameter.
29
+ #
30
+ # Example:
31
+ # body(:plain, "hello") # => sets the 'plain' body to "hello"
32
+ #
33
+ # If called with just one parameter it will return the value of that body type. If the value is nil
34
+ # the template for that body type will be rendered.
35
+ #
36
+ # Example:
37
+ # body(:plain) # => "hello"
38
+ # body(:html) # => will call the html.erb template for this notifier.
39
+ def body(part, value = nil)
40
+ part = part.to_sym
41
+ if value.nil?
42
+ body = bodies[part]
43
+ if body.blank?
44
+ bodies[part] = build_template(part)
45
+ return bodies[part]
46
+ else
47
+ return body
48
+ end
49
+ else
50
+ bodies[part] = value
51
+ end
52
+ end
53
+
54
+ # Returns the mime_version of the notification, defaults to "1.0"
55
+ def mime_version
56
+ (@mime_version ||= "1.0")
57
+ end
58
+
59
+ # This will attempt to determine the content type of the notification, unless one is already specified.
60
+ def content_type
61
+ return @content_type unless @content_type.blank?
62
+ if has_attachments?
63
+ return "multipart/mixed"
64
+ elsif !body(:plain).blank? && !body(:html).blank?
65
+ return "multipart/alternative"
66
+ elsif body(:html)
67
+ return "text/html"
68
+ else
69
+ return "text/plain"
70
+ end
71
+ end
72
+
73
+ # Returns the date sent, defaults to Time.now
74
+ def date_sent
75
+ (@date_sent ||= Time.now)
76
+ end
77
+
78
+ # Returns the reply to address, defaults to the from address.
79
+ def reply_to
80
+ (@reply_to || self.from)
81
+ end
82
+
83
+ # Adds a BlabberMouth::Attachment to the notifier.
84
+ # Raise ArgumentError if the parameter is not a BlabberMouth::Attachment
85
+ def attach(file)
86
+ raise ArgumentError.new unless file.is_a?(BlabberMouth::Attachment)
87
+ attachments << file
88
+ end
89
+
90
+ # Returns true if there are attachments.
91
+ def has_attachments?
92
+ !attachments.empty?
93
+ end
94
+
95
+ # Returns the attachments Array.
96
+ def attachments
97
+ @attachments ||= []
98
+ end
99
+
100
+ # Delivers the notification with the configured BlabberMouth::DeliveryHandlers class.
101
+ # Returns false if there are any errors.
102
+ def deliver(handler = deliver_with)
103
+ begin
104
+ deliver!(handler)
105
+ rescue Exception => e
106
+ return false
107
+ end
108
+ return true
109
+ end
110
+
111
+ # Delivers the email with the configured BlabberMouth::DeliveryHandlers class.
112
+ def deliver!(handler = deliver_with)
113
+ "BlabberMouth::DeliveryHandlers::#{handler.to_s.camelcase}".constantize.deliver(self)
114
+ end
115
+
116
+ # Returns all the recipients of this notifier.
117
+ def recipients
118
+ [self.to, self.cc, self.bcc].flatten.compact
119
+ end
120
+
121
+ # Returns a ready to be delivered, encoded, version of the notification.
122
+ def deliverable(adap = adapter)
123
+ adap = "BlabberMouth::Adapters::#{adap.to_s.camelcase}".constantize.new(self)
124
+ adap.convert
125
+ adap.deliverable
126
+ end
127
+
128
+ # This method returns the adapter that will transform the BlabberMouth object
129
+ # and prepare it for delivery. This method returns the configatron.notifier.adapter
130
+ # parameter. Override this in your BlabberMouth class to specify a different adapter
131
+ # or change the configatron parameter to globally affect all your Notifiers.
132
+ #
133
+ # Default: :tmail
134
+ def adapter
135
+ configatron.blabber_mouth.adapter
136
+ end
137
+
138
+ # This method returns the delivery handler that will delivers the BlabberMouth object.
139
+ # This method returns the configatron.blabber_mouth.deliver_with parameter. Override this in
140
+ # your BlabberMouth class to specify a different handler or change the configatron
141
+ # parameter to globally affect all your Notifiers.
142
+ #
143
+ # Default: :sendmail
144
+ def deliver_with
145
+ configatron.blabber_mouth.deliver_with
146
+ end
147
+
148
+ private
149
+ def bodies
150
+ @bodies ||= {}
151
+ end
152
+
153
+ def build_template(format)
154
+ path = File.join(configatron.blabber_mouth.paths.templates, self.class.to_s.underscore, "#{format}.erb")
155
+ if File.exists?(path)
156
+ template = ERB.new(File.read(path))
157
+ return template.result(Template.new(self).binder)
158
+ end
159
+ # begin
160
+ # vt = BlabberMouth::Rendering::ViewTemplate.new(:notifier, self.class.to_s.underscore, {:locals => {:notifier => self}, :format => format.to_s})
161
+ # return vt._compile_and_render
162
+ # rescue BlabberMouth::Errors::ResourceNotFound => e
163
+ # end
164
+ return nil
165
+ end
166
+
167
+ class Template
168
+
169
+ attr_accessor :notifier
170
+
171
+ def initialize(notifier)
172
+ self.notifier = notifier
173
+ end
174
+
175
+ def binder
176
+ binding
177
+ end
178
+
179
+ end
180
+
181
+ end # BlabberMouth
@@ -0,0 +1,19 @@
1
+ module BlabberMouth
2
+ module DeliveryHandlers # :nodoc:
3
+ # Delivers BlabberMouth objects using sendmail.
4
+ module Sendmail
5
+
6
+ def self.deliver(mail)
7
+ sendmail_settings = configatron.blabber_mouth.sendmail
8
+ sendmail_args = sendmail_settings.arguments
9
+ sendmail_args += " -f \"#{mail.reply_to}\"" if mail.reply_to
10
+ IO.popen("#{sendmail_settings.location} #{sendmail_args}","w+") do |sm|
11
+ sm.print(mail.deliverable.gsub(/\r/, ''))
12
+ sm.flush
13
+ end
14
+ end
15
+
16
+ end # Sendmail
17
+
18
+ end # DeliveryHandlers
19
+ end # BlabberMouth
@@ -0,0 +1,18 @@
1
+ require 'net/smtp'
2
+ module BlabberMouth
3
+ module DeliveryHandlers # :nodoc:
4
+ # Delivers BlabberMouth objects using Net::SMTP.
5
+ module Smtp
6
+
7
+ def self.deliver(mail)
8
+ smtp_settings = configatron.blabber_mouth.smtp
9
+ Net::SMTP.start(smtp_settings.address, smtp_settings.port,
10
+ smtp_settings.domain, smtp_settings.retrieve(:user_name, nil),
11
+ smtp_settings.retrieve(:password, nil), smtp_settings.retrieve(:authentication, nil)) do |smtp|
12
+ smtp.sendmail(mail.deliverable, mail.reply_to, mail.recipients)
13
+ end
14
+ end
15
+
16
+ end # Smtp
17
+ end # DeliveryHandlers
18
+ end # BlabberMouth
@@ -0,0 +1,15 @@
1
+ module BlabberMouth
2
+ module DeliveryHandlers # :nodoc:
3
+ # Delivers BlabberMouth objects to an Array.
4
+ module Test
5
+
6
+ def self.deliver(notifier)
7
+ NotifierRegistry.add(notifier)
8
+ end
9
+
10
+ class NotifierRegistry < BlabberMouth::Utils::RegistryList # :nodoc:
11
+ end
12
+
13
+ end # Test
14
+ end # DeliveryHandlers
15
+ end # BlabberMouth
@@ -0,0 +1,76 @@
1
+ module BlabberMouth
2
+ module DeliveryHandlers # :nodoc:
3
+ # Delivers BlabberMouth objects using XMPP (Jabber)
4
+ module XmppTransport
5
+
6
+ def self.check_availability(client, recipients)
7
+ buddies = {}
8
+ recipients.each do |rcpt|
9
+ buddies[rcpt] = :offline
10
+ end
11
+
12
+ # try to get the presence update
13
+ sleep(1)
14
+ client.presence_updates do |update|
15
+ from = update[0].to_s
16
+ presence = update[1].to_s
17
+ if buddies.has_key?(from)
18
+ buddies[from] = presence
19
+ end
20
+ Mack.logger.info "#{from} --> #{presence}"
21
+ end
22
+ return buddies
23
+ end
24
+
25
+ def self.deliver_message(client, xmpp_msg, wait_for_response, xmpp_errors)
26
+ Mack.logger.info "#{xmpp_msg.to} is online, delivering message"
27
+ client.deliver(xmpp_msg.to, xmpp_msg)
28
+ loop do
29
+ client.received_messages { |ret_msg| @msg_received = true if ret_msg.body == "ack" }
30
+ break if @msg_received or @error
31
+ end if wait_for_response
32
+ return xmpp_errors
33
+ end
34
+
35
+ def self.deliver(xmpp_msg)
36
+ @ex ||= BlabberMouth::Errors::XmppError.new("xmpp error")
37
+ xmpp_settings = configatron.blabber_mouth.xmpp
38
+ jid_str = xmpp_settings.jid
39
+ jid_str += ("/" + xmpp_settings.jid_resource) if !jid_str.index("/")
40
+ password = xmpp_settings.password
41
+ client = Jabber::Simple.new(jid_str, password)
42
+ thr = Thread.new {
43
+ begin
44
+ xmpp_msg = xmpp_msg.deliverable
45
+ Timeout::timeout(20) do
46
+ buddies = check_availability(client, xmpp_msg.recipients)
47
+
48
+ online_buddies = buddies.keys.reject { |x| buddies[x].to_sym == :offline }
49
+ offline_buddies = buddies.keys.reject { |x| buddies[x].to_sym == :online }
50
+
51
+ if !offline_buddies.empty?
52
+ # there are offline buddies, log the errors
53
+ offline_buddies.each do |buddy|
54
+ err = BlabberMouth::Errors::XmppUserNotOnline.new(buddy)
55
+ @ex.add_error(:offline, err)
56
+ end
57
+ end
58
+
59
+ online_buddies.each do |buddy|
60
+ deliver_message(client, xmpp_msg.find_message_by_recipient(buddy), xmpp_settings.wait_for_response, @ex)
61
+ end
62
+
63
+ raise @ex if !@ex.empty?
64
+ end # timeout
65
+ rescue Timeout::Error => ex
66
+ @error = ex
67
+ rescue Exception => ex
68
+ end
69
+ }
70
+
71
+ thr.join
72
+ raise @ex if !@ex.empty?
73
+ end
74
+ end # XmppTransport
75
+ end # DeliveryHandlers
76
+ end # BlabberMouth
@@ -0,0 +1,55 @@
1
+ module BlabberMouth
2
+ module Errors # :nodoc:
3
+
4
+ class UnconvertedNotifier < StandardError
5
+ def initialize # :nodoc:
6
+ super("You must convert the BlabberMouth object first!")
7
+ end
8
+ end # UnconvertedNotifier
9
+
10
+ class XmppError < StandardError
11
+ def initialize(msg)
12
+ super(msg)
13
+ self.error_hash = {}
14
+ end
15
+
16
+ def add_error(type, msg)
17
+ self.error_hash[type] ||= []
18
+ self.error_hash[type] << msg
19
+ end
20
+
21
+ def get_error(type)
22
+ self.error_hash[type]
23
+ end
24
+
25
+ def empty?
26
+ self.error_hash.empty?
27
+ end
28
+
29
+ attr_accessor :error_hash
30
+ end
31
+
32
+ class XmppAuthenticationError < StandardError
33
+ def initialize(user)
34
+ super("Cannot authenticate: #{user} to xmpp server")
35
+ end
36
+ end
37
+
38
+ class XmppUserNotOnline < StandardError
39
+ def initialize(user)
40
+ super("user #{user} is not online")
41
+ end
42
+ end
43
+
44
+ class XmppSendError < StandardError
45
+ attr_reader :code
46
+ attr_reader :msg
47
+
48
+ def initialize(code, msg)
49
+ super("Cannot send message. Code=#{code}, Msg=#{msg}")
50
+ @code = code
51
+ @msg = msg
52
+ end
53
+ end
54
+ end # Errors
55
+ end # BlabberMouth
@@ -0,0 +1,8 @@
1
+ # If the notifiers directory does not exist, create it.
2
+ path = configatron.blabber_mouth.paths.models
3
+ FileUtils.mkdir_p(path)
4
+
5
+ # Require all notifiers
6
+ Dir.glob(File.join(path, "**/*.rb")).each do |notifier|
7
+ require File.expand_path(notifier)
8
+ end
@@ -0,0 +1,12 @@
1
+ notifier_template:
2
+ type: file
3
+ template_path: <%= File.join(templates_directory_path, "app", "notifiers", "notifier.rb.template") %>
4
+ output_path: <%= File.join(configatron.blabber_mouth.paths.models, "#{file_name}.rb") %>
5
+ text_template:
6
+ type: file
7
+ template_path: <%= File.join(templates_directory_path, "app", "notifiers", "plain.erb.template") %>
8
+ output_path: <%= File.join(configatron.blabber_mouth.paths.templates, file_name, "plain.erb") %>
9
+ html_template:
10
+ type: file
11
+ template_path: <%= File.join(templates_directory_path, "app", "notifiers", "html.erb.template") %>
12
+ output_path: <%= File.join(configatron.blabber_mouth.paths.templates, file_name, "html.erb") %>
@@ -0,0 +1,23 @@
1
+ # Generates the necessary files for a basic notifier.
2
+ #
3
+ # Example:
4
+ # rake generate:notifier name=welcome_email
5
+ # generates the following files:
6
+ # app/notifiers/welcome_email.rb
7
+ # app/notifiers/templates/welcome_email/text.erb
8
+ # app/notifiers/templates/welcome_email/html.erb
9
+ # test/unit/welcome_email_spec.rb # => if using RSpec
10
+ # test/unit/welcome_email_test.rb # => if using Test::Unit::TestCase
11
+ class NotifierGenerator < Genosaurus
12
+
13
+ require_param :name
14
+
15
+ def file_name # :nodoc:
16
+ param(:name).underscore.downcase
17
+ end
18
+
19
+ def class_name # :nodoc:
20
+ param(:name).camelcase
21
+ end
22
+
23
+ end
@@ -0,0 +1,2 @@
1
+ <!-- Use this file to create your HTML version of your email.
2
+ Access to your BlabberMouth class is available via the notifier method. -->
@@ -0,0 +1,3 @@
1
+ class <%= class_name %>
2
+ include BlabberMouth
3
+ end
@@ -0,0 +1,2 @@
1
+ # Use this file to create your plain text version of your email.
2
+ # Access to your BlabberMouth class is available via the notifier method.
@@ -0,0 +1,14 @@
1
+ # module Rendering # :nodoc:
2
+ # module Type # :nodoc:
3
+ # class Notifier < BlabberMouth::Rendering::Type::FileBase # :nodoc:
4
+ #
5
+ # def render
6
+ # x_file = BlabberMouth::Paths.notifier_templates(self._render_value, self._options[:format])
7
+ # render_file(x_file)
8
+ # end
9
+ #
10
+ # end # BlabberMouth
11
+ # end # Type
12
+ # end # Rendering
13
+ #
14
+ # BlabberMouth::Rendering::Engine::Registry.instance.register(:notifier, :erb)
@@ -0,0 +1,28 @@
1
+ if defined?(RAILS_ENV)
2
+ configatron.blabber_mouth.set_default(:env, RAILS_ENV)
3
+ configatron.blabber_mouth.paths.set_default(:models, File.join(RAILS_ROOT, 'app', 'notifiers'))
4
+ configatron.blabber_mouth.paths.set_default(:templates, File.join(RAILS_ROOT, 'app', 'notifiers', 'templates'))
5
+ else
6
+ configatron.blabber_mouth.set_default(:env, 'development')
7
+ configatron.blabber_mouth.paths.set_default(:models, File.join(FileUtils.pwd, 'app', 'notifiers'))
8
+ configatron.blabber_mouth.paths.set_default(:templates, File.join(FileUtils.pwd, 'app', 'notifiers', 'templates'))
9
+ end
10
+
11
+ configatron.blabber_mouth.paths.set_default(:templates, File.join(configatron.blabber_mouth.paths.models, 'templates'))
12
+
13
+ configatron.blabber_mouth.sendmail.set_default(:location, '/usr/sbin/sendmail')
14
+ configatron.blabber_mouth.sendmail.set_default(:arguments, '-i -t')
15
+ configatron.blabber_mouth.smtp.set_default(:address, 'localhost')
16
+ configatron.blabber_mouth.smtp.set_default(:port, 25)
17
+ configatron.blabber_mouth.smtp.set_default(:domain, 'localhost.localdomain')
18
+ configatron.blabber_mouth.set_default(:deliver_with, (configatron.blabber_mouth.env == "test" ? "test" : "smtp"))
19
+ configatron.blabber_mouth.set_default(:adapter, 'tmail')
20
+
21
+ # xmpp settings
22
+ configatron.blabber_mouth.xmpp.set_default(:jid, 'h_test@jabber80.com')
23
+ configatron.blabber_mouth.xmpp.set_default(:jid_resource, 'work')
24
+ configatron.blabber_mouth.xmpp.set_default(:password, 'test1234')
25
+ configatron.blabber_mouth.xmpp.set_default(:message_type, :chat)
26
+ configatron.blabber_mouth.xmpp.set_default(:wait_for_response, true)
27
+ configatron.blabber_mouth.xmpp.set_default(:response_wait_time, 20)
28
+ configatron.blabber_mouth.xmpp.set_default(:response_message, "ack")
@@ -0,0 +1,47 @@
1
+ if configatron.blabber_mouth.env == "test"
2
+
3
+ # Used for testing this method will return any emails that have been 'sent' using BlabberMouth::DeliveryHandlers::Test.
4
+ # These emails will get 'flushed' after each test.
5
+ def delivered_notifiers
6
+ BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.registered_items
7
+ end
8
+
9
+ if defined?(Spec)
10
+
11
+ Spec::Runner.configure do |config|
12
+
13
+ config.before(:each) do
14
+ BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.reset!
15
+ end
16
+
17
+ config.after(:each) do
18
+ BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.reset!
19
+ end
20
+
21
+ end
22
+
23
+ else
24
+
25
+ module Test # :nodoc:
26
+ module Unit # :nodoc:
27
+ class TestCase # :nodoc:
28
+
29
+ # Let's alias the run method in the class above us so we can create a new one here
30
+ # but still reference it.
31
+ alias_instance_method :run, :super_run
32
+
33
+ # We need to wrap the run method so we can do things like
34
+ # run a cleanup method if it exists
35
+ def run(result, &progress_block) # :nodoc:
36
+ @__res = super_run(result)
37
+ BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.reset!
38
+ @__res
39
+ end
40
+
41
+ end # TestCase
42
+ end # Unit
43
+ end # Test
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,82 @@
1
+ require 'singleton'
2
+ module BlabberMouth
3
+ module Utils
4
+ # This is a general purpose Singleton Registry class.
5
+ # It takes the drudgery out of creating registry classes, that
6
+ # are, let's face it, all pretty much the same.
7
+ class RegistryList
8
+ include Singleton
9
+
10
+ # The list of registered items
11
+ attr_reader :registered_items
12
+
13
+ def initialize # :nodoc:
14
+ reset!
15
+ end
16
+
17
+ # Override this method to set the initial state of the registered_items Array.
18
+ # By default this list is empty.
19
+ def initial_state
20
+ []
21
+ end
22
+
23
+ # Resets the registered_items list to the list specified by the initial_state method.
24
+ def reset!
25
+ @registered_items = self.initial_state.dup
26
+ end
27
+
28
+ # Adds an object to the list at a specified position. By default the position is last.
29
+ def add(klass, position = self.registered_items.size)
30
+ self.registered_items.insert(position, klass)
31
+ self.registered_items.uniq!
32
+ self.registered_items.compact!
33
+ end
34
+
35
+ # Removes an object from the list.
36
+ def remove(klass)
37
+ self.registered_items.delete(klass)
38
+ end
39
+
40
+ class << self
41
+
42
+ # Returns the list of registered items.
43
+ def registered_items
44
+ self.instance.registered_items
45
+ end
46
+
47
+ # Emptys out the list of registered_items.
48
+ def clear!
49
+ registered_items.clear
50
+ end
51
+
52
+ # Resets the registered_items list to the list specified by the initial_state method.
53
+ def reset!
54
+ self.instance.reset!
55
+ end
56
+
57
+ # Adds an object to the list at a specified position. By default the position is last.
58
+ def add(klass, position = registered_items.size)
59
+ self.instance.add(klass, position)
60
+ end
61
+
62
+ # Removes an object from the list.
63
+ def remove(klass)
64
+ self.instance.remove(klass)
65
+ end
66
+
67
+ # Moves an object to the top of the registered_items list.
68
+ def move_to_top(klass)
69
+ self.instance.add(klass, 0)
70
+ end
71
+
72
+ # Moves an object to the bottom of the registered_items list.
73
+ def move_to_bottom(klass)
74
+ remove(klass)
75
+ self.instance.add(klass)
76
+ end
77
+
78
+ end
79
+
80
+ end # RegistryList
81
+ end # Utils
82
+ end # BlabberMouth
@@ -0,0 +1,97 @@
1
+ module BlabberMouth
2
+ # Includes the validatable gem into your Notifier.
3
+ # http://validatable.rubyforge.org
4
+ module Validatable
5
+
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ include ::Validatable
9
+ alias_method "unvalidated_deliver!", "deliver!"
10
+ end
11
+
12
+ base.class_eval do
13
+
14
+ class << self
15
+
16
+ # Adds common validations to your BlabberMouth class.
17
+ # These include:
18
+ # validates_presence_of :to
19
+ # validates_presence_of :from
20
+ # validates_presence_of :subject
21
+ # validates_email_format_of :to
22
+ # validates_email_format_of :from
23
+ def common_notifier_validations
24
+ validates_presence_of :to
25
+ validates_presence_of :from
26
+ validates_presence_of :subject
27
+ validates_email_format_of :to
28
+ validates_email_format_of :from
29
+ end
30
+
31
+ # Validates the email format of the column specified against the email_validation_regex method.
32
+ # This will drill into arrays as well, if that's what your column is.
33
+ def validates_email_format_of(column, options = {})
34
+ options = {:logic => lambda{
35
+ [send(column)].flatten.each_with_index do |addr, i|
36
+ errors.add(column, "[#{addr}] is not valid") unless addr.to_s.downcase.match(self.class.email_validation_regex)
37
+ end
38
+ }}.merge(options)
39
+ validates_each :to, options
40
+ end
41
+
42
+ def email_validation_regex
43
+ regex = <<-EOF
44
+ [a-z0-9!#$\%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$\%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
45
+ EOF
46
+ /#{regex.strip}/
47
+ end
48
+
49
+ end # class << self
50
+ end # class_eval
51
+ end # included
52
+
53
+ # Raises a RuntimeError if the email you are trying to deliver is not valid.
54
+ def deliver!(handler = deliver_with)
55
+ raise 'Notification is Invalid!' unless self.valid?
56
+ unvalidated_deliver!(handler)
57
+ end
58
+
59
+ # Returns false if the email is not valid.
60
+ # If the email is valid and an exception is raised when trying to deliver it
61
+ # false is returned and the exception is added to the errors array, with the
62
+ # key :deliver.
63
+ def deliver(handler = deliver_with)
64
+ return false unless self.valid?
65
+ begin
66
+ "BlabberMouth::DeliveryHandlers::#{handler.to_s.camelcase}".constantize.deliver(self)
67
+ rescue Exception => e
68
+ self.errors.add(:deliver, e.message)
69
+ return false
70
+ end
71
+ return true
72
+ end
73
+
74
+ def errors_for(name)
75
+ self.errors.on(name.to_sym)
76
+ end
77
+
78
+ end # Validatable
79
+ end # BlabberMouth
80
+
81
+ module Validatable # :nodoc:
82
+ class ValidationBase #:nodoc:
83
+
84
+ # This fixes a bug with reloading of Validatable classes.
85
+ def raise_error_if_key_is_dup(klass) # :nodoc:
86
+ vals = {}
87
+ klass.validations.each do |v|
88
+ vals[v.key] = v
89
+ end
90
+ klass.validations.clear
91
+ vals.each do |k,v|
92
+ klass.validations << v
93
+ end
94
+ end # raise_error_if_key_is_dup
95
+
96
+ end # ValidationBase
97
+ end # Validatable
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: markbates-blabber_mouth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.20090714164111
5
+ platform: ruby
6
+ authors:
7
+ - markbates
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-14 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: tmail
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.3.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: validatable
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.6.7
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: xmpp4r
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "="
42
+ - !ruby/object:Gem::Version
43
+ version: "0.4"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: xmpp4r-simple
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.8.8
54
+ version:
55
+ description: "blabber_mouth was developed by: markbates"
56
+ email: ""
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - README
63
+ - LICENSE
64
+ files:
65
+ - lib/blabber_mouth/adapters/base.rb
66
+ - lib/blabber_mouth/adapters/tmail.rb
67
+ - lib/blabber_mouth/adapters/xmpp_msg.rb
68
+ - lib/blabber_mouth/attachment.rb
69
+ - lib/blabber_mouth/blabber_mouth.rb
70
+ - lib/blabber_mouth/delivery_handlers/sendmail.rb
71
+ - lib/blabber_mouth/delivery_handlers/smtp.rb
72
+ - lib/blabber_mouth/delivery_handlers/test.rb
73
+ - lib/blabber_mouth/delivery_handlers/xmpp_transport.rb
74
+ - lib/blabber_mouth/errors.rb
75
+ - lib/blabber_mouth/loader.rb
76
+ - lib/blabber_mouth/notifier_generator/manifest.yml
77
+ - lib/blabber_mouth/notifier_generator/notifier_generator.rb
78
+ - lib/blabber_mouth/notifier_generator/templates/app/notifiers/html.erb.template
79
+ - lib/blabber_mouth/notifier_generator/templates/app/notifiers/notifier.rb.template
80
+ - lib/blabber_mouth/notifier_generator/templates/app/notifiers/plain.erb.template
81
+ - lib/blabber_mouth/rendering/type/mailer.rb
82
+ - lib/blabber_mouth/settings.rb
83
+ - lib/blabber_mouth/testing.rb
84
+ - lib/blabber_mouth/utils/registry_list.rb
85
+ - lib/blabber_mouth/validations.rb
86
+ - lib/blabber_mouth.rb
87
+ - README
88
+ - LICENSE
89
+ has_rdoc: false
90
+ homepage: ""
91
+ post_install_message:
92
+ rdoc_options: []
93
+
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ version:
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: "0"
107
+ version:
108
+ requirements: []
109
+
110
+ rubyforge_project: magrathea
111
+ rubygems_version: 1.2.0
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: blabber_mouth
115
+ test_files: []
116
+