postageapp 1.2.0 → 1.2.5

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.
@@ -18,13 +18,15 @@
18
18
  #
19
19
  # Postage::Mailer introduces a few mailer methods specific to Postage:
20
20
  #
21
- # * postageapp_template - template name that is defined in your PostageApp project
21
+ # * postageapp_template - template name that is defined in your PostageApp project
22
22
  # * postageapp_variables - extra variables you want to send along with the message
23
23
  #
24
24
  # Sending email
25
25
  #
26
- # request = Notifier.signup_notification(user) # creates PostageApp::Request object
27
- # response = request.deliver # attempts to deliver the message and creates a PostageApp::Response
26
+ # # Create a PostageApp::Request object
27
+ # request = Notifier.signup_notification(user)
28
+ # # Deliver the message and return a PostageApp::Response
29
+ # response = request.deliver_now
28
30
 
29
31
  class PostageApp::Mailer < ActionMailer::Base
30
32
  CONTENT_TYPE_MAP = {
@@ -128,9 +130,6 @@ class PostageApp::Mailer < ActionMailer::Base
128
130
  @_mail_was_called = true
129
131
  m = @_message
130
132
 
131
- # At the beginning, do not consider class default for parts order neither content_type
132
- content_type = headers[:content_type]
133
-
134
133
  # Call all the procs (if any)
135
134
  class_default = self.class.default
136
135
  default_values = class_default.merge(self.class.default) do |k,v|
@@ -140,9 +139,6 @@ class PostageApp::Mailer < ActionMailer::Base
140
139
  # Handle defaults
141
140
  headers = headers.reverse_merge(default_values)
142
141
 
143
- # Apply charset at the beginning so all fields are properly quoted
144
- charset = headers[:charset]
145
-
146
142
  # Set configure delivery behavior
147
143
  wrap_delivery_behavior!(
148
144
  headers.delete(:delivery_method),
@@ -201,7 +197,7 @@ class PostageApp::Request
201
197
 
202
198
  # Either doing an actual send, or passing it along to Mail::TestMailer
203
199
  # Probably not the best way as we're skipping way too many intermediate methods
204
- def deliver
200
+ def deliver_now
205
201
  inform_interceptors
206
202
 
207
203
  if (perform_deliveries)
@@ -212,6 +208,7 @@ class PostageApp::Request
212
208
  end
213
209
  end
214
210
  end
211
+ alias_method :deliver, :deliver_now
215
212
 
216
213
  # Not 100% on this, but I need to assign this so I can properly handle deliver method
217
214
  def delivery_method(method = nil, settings = nil)
@@ -7,12 +7,12 @@ class PostageApp::Request
7
7
  }
8
8
 
9
9
  # Unique ID (UID) for the request
10
- attr_accessor :uid
10
+ attr_writer :uid
11
11
 
12
12
  # The API method being called (example: send_message)
13
13
  # This controls the url of the request (example: https://api.postageapp.com/v.1.0/send_message.json)
14
14
  attr_accessor :method
15
-
15
+
16
16
  # A list of arguments in a Hash format passed along with the request
17
17
  attr_accessor :arguments
18
18
 
@@ -30,9 +30,9 @@ class PostageApp::Request
30
30
  end
31
31
 
32
32
  # Creates a new Request with the given API call method and arguments.
33
- def initialize(method, arguments = { })
33
+ def initialize(method, arguments = nil)
34
34
  @method = method
35
- @arguments = arguments.dup
35
+ @arguments = arguments ? arguments.dup : { }
36
36
 
37
37
  @uid = @arguments.delete('uid')
38
38
  @api_key = @arguments.delete('api_key') || PostageApp.configuration.api_key
@@ -110,18 +110,131 @@ class PostageApp::Request
110
110
  hash
111
111
  end
112
112
 
113
- # Emulation of Mail::Message interface
114
- def body
115
- self.arguments and self.arguments['content'] and (self.arguments['content']['text/html'] or self.arguments['content']['text/plain'])
113
+ def content
114
+ self.arguments['content'] ||= { }
116
115
  end
117
116
 
118
- # Emulates Mail::Message#html_part
117
+ # -- Mail::Message Emulation ----------------------------------------------
118
+
119
119
  def html_part
120
- self.arguments and self.arguments['content'] and self.arguments['content']['text/html']
120
+ self.content['text/html']
121
121
  end
122
122
 
123
- # Emulates Mail::Message#text_part
124
123
  def text_part
125
- self.arguments and self.arguments['content'] and self.arguments['content']['text/plain']
124
+ self.content['text/plain']
125
+ end
126
+
127
+ def find_first_mime_type(type)
128
+ self.content[type]
129
+ end
130
+
131
+ def mime_type
132
+ self.content.keys.first
133
+ end
134
+
135
+ def header
136
+ self.arguments['headers'] ||= { }
137
+ end
138
+
139
+ def reply_to
140
+ self.header['reply-to']
141
+ end
142
+
143
+ def cc
144
+ self.header['cc']
145
+ end
146
+
147
+ def attachments
148
+ self.arguments['attachments']
149
+ end
150
+
151
+ def multipart?
152
+ self.content.keys.length > 1
153
+ end
154
+
155
+ # Getter and setter for headers. You can specify headers in the following
156
+ # formats:
157
+ # headers['Custom-Header'] = 'Custom Value'
158
+ # headers 'Custom-Header-1' => 'Custom Value 1',
159
+ # 'Custom-Header-2' => 'Custom Value 2'
160
+ def headers(value = nil)
161
+ _headers = self.arguments['headers'] ||= { }
162
+
163
+ case (value)
164
+ when Hash
165
+ value.each do |k, v|
166
+ _headers[k.to_s] = v.to_s
167
+ end
168
+ end
169
+
170
+ _headers
171
+ end
172
+
173
+ def [](key)
174
+ case (key)
175
+ when :to, 'to'
176
+ self.to
177
+ when :from, 'from'
178
+ self.from
179
+ when :bcc, 'bcc'
180
+ # Not supported via API at this time
181
+ [ ]
182
+ end
183
+ end
184
+
185
+ def to
186
+ out = self.arguments_to_send.dig('arguments', 'recipients')
187
+
188
+ case (out)
189
+ when Hash
190
+ out
191
+ else
192
+ [ out ].flatten
193
+ end
194
+ end
195
+
196
+ def to=(list)
197
+ self.arguments['recipients'] = list
198
+ end
199
+
200
+ def from
201
+ [ self.arguments_to_send.dig('arguments', 'headers', 'from') ].flatten
202
+ end
203
+
204
+ def from=(address)
205
+ _headers = self.arguments['headers'] ||= { }
206
+
207
+ _headers['from'] = address.to_s
208
+ end
209
+
210
+ def bcc
211
+ # Not supported natively via API at this time
212
+ [ ]
213
+ end
214
+
215
+ def bcc=(list)
216
+ # Not supported natively via API at this time
217
+ end
218
+
219
+ def subject
220
+ self.arguments_to_send.dig('arguments', 'headers', 'subject')
221
+ end
222
+
223
+ def subject=(subject)
224
+ _headers = self.arguments['headers'] ||= { }
225
+
226
+ _headers['subject'] = subject.to_s
227
+ end
228
+
229
+ # # Emulation of Mail::Message interface
230
+ # def body
231
+ # _content = self.arguments && self.arguments['content']
232
+
233
+ # _content and (_content['text/html'] or _content['text/plain'])
234
+ # end
235
+
236
+ def body
237
+ out = self.arguments_to_send.dig('arguments', 'content')
238
+ out.is_a?(Hash) ? out.values.join("\n\n") : out.to_s
126
239
  end
127
240
  end
@@ -13,6 +13,8 @@ class PostageApp::Response
13
13
  # The data payload of the response. This is usually the return value of the
14
14
  # request we're looking for
15
15
  attr_reader :data
16
+
17
+ attr_reader :exception
16
18
 
17
19
  # Takes in Net::HTTPResponse object as the attribute.
18
20
  # If something goes wrong Response will be thought of as failed
@@ -27,8 +29,9 @@ class PostageApp::Response
27
29
 
28
30
  @data = hash['data']
29
31
 
30
- rescue
32
+ rescue => e
31
33
  @status = 'fail'
34
+ @exception = '[%s] %s' % [ e.class, e ]
32
35
  end
33
36
 
34
37
  # Little helper that checks for the Response status
@@ -1,37 +1,42 @@
1
1
  class Hash
2
- # Example usage:
3
- # @hash.dig(:k1) # same as @hash[:k1]
4
- # @hash.dig(:k1, :k2) # same as @hash[:k1] && @hash[:k1][:k2]
5
- # @hash.dig(:k1, :k2, k3) # same as @hash[:k1] && @hash[:k1][:k2] && @hash[:k1][:k2][:k3]
6
- def dig(*path)
7
- path.inject(self) do |location, key|
8
- location.respond_to?(:keys) ? location[key] : nil
2
+ # Ruby 2.3.0 adds the dig method so this needs to be conditional.
3
+ unless ((instance_methods & [ :dig ]).any?)
4
+ # Example usage:
5
+ # @hash.dig(:k1) # same as @hash[:k1]
6
+ # @hash.dig(:k1, :k2) # same as @hash[:k1] && @hash[:k1][:k2]
7
+ # @hash.dig(:k1, :k2, k3) # same as @hash[:k1] && @hash[:k1][:k2] && @hash[:k1][:k2][:k3]
8
+ def dig(*path)
9
+ path.inject(self) do |location, key|
10
+ location.respond_to?(:keys) ? location[key] : nil
11
+ end
9
12
  end
10
13
  end
11
14
 
12
- # Destructively convert all keys to strings.
13
- def recursive_stringify_keys!
14
- keys.each do |key|
15
- value = delete(key)
15
+ unless ((instance_methods & [ :recursive_stringify_keys! ]).any?)
16
+ # Destructively convert all keys to strings.
17
+ def recursive_stringify_keys!
18
+ keys.each do |key|
19
+ value = delete(key)
16
20
 
17
- self[key.to_s] =
18
- case (value)
19
- when Hash
20
- value.recursive_stringify_keys!
21
- else
22
- value
23
- end
24
- end
21
+ self[key.to_s] =
22
+ case (value)
23
+ when Hash
24
+ value.recursive_stringify_keys!
25
+ else
26
+ value
27
+ end
28
+ end
25
29
 
26
- self
30
+ self
31
+ end
27
32
  end
28
33
  end
29
34
 
30
35
  class Net::HTTP
31
36
  # Getting rid of the 'warning: peer certificate won't be verified in this SSL session'
32
- alias_method :old_initialize, :initialize
37
+ alias_method :__initialize, :initialize
33
38
  def initialize(*args)
34
- old_initialize(*args)
39
+ __initialize(*args)
35
40
 
36
41
  @ssl_context = OpenSSL::SSL::SSLContext.new
37
42
  @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -1,3 +1,3 @@
1
1
  module PostageApp
2
- VERSION = "1.2.0"
2
+ VERSION = '1.2.5'.freeze
3
3
  end
@@ -1,16 +1,25 @@
1
1
  # encoding: utf-8
2
2
 
3
- $:.unshift File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
4
4
  require 'postageapp/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "postageapp"
8
8
  s.version = PostageApp::VERSION
9
- s.authors = [ "Oleg Khabarov", "Scott Tadman", "The Working Group Inc." ]
10
- s.email = [ "oleg@khabarov.ca", "tadman@postageapp.com" ]
9
+ s.authors = [
10
+ "Oleg Khabarov",
11
+ "Scott Tadman",
12
+ "The Working Group Inc."
13
+ ]
14
+ s.email = [
15
+ "oleg@khabarov.ca",
16
+ "tadman@postageapp.com"
17
+ ]
18
+
11
19
  s.homepage = "http://github.com/postageapp/postageapp-ruby"
12
- s.summary = "Easier way to send email from web apps"
13
- s.description = "Gem that interfaces with PostageApp.com service to send emails from web apps"
20
+
21
+ s.summary = "Gem for communicating with the PostageApp email API"
22
+ s.description = "Gem that interfaces with PostageApp service to send emails from Ruby applications"
14
23
  s.license = 'MIT'
15
24
 
16
25
  s.files = `git ls-files`.split("\n")
@@ -20,4 +29,5 @@ Gem::Specification.new do |s|
20
29
  s.required_ruby_version = '>= 1.9.3'
21
30
 
22
31
  s.add_dependency 'json'
32
+ s.add_dependency 'mail'
23
33
  end
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This script can be used to engage a particular Gemfile for the purposes of
4
+ # continuous integration testing.
5
+ #
6
+ # Usage: script/with <variant> <env|bootstrap|bundle|rake>
7
+ #
8
+ # Here <variant> refers to a pre-defined Gemfile located in test/gemfiles
9
+ # and the commands include:
10
+ #
11
+ # * env - Display the current BUNDLE_GEMFILE environment
12
+ # * bootstrap - Install the necessary hard dependencies (rubygems, bundler)
13
+ # * bundle - Execute arbitrary Bundler command
14
+ # * rake - Execute arbitrary rake command via `bundle exec`
15
+ #
16
+ # Examples:
17
+ # * script/with rails-3.0.x bootstrap
18
+ # * script/with rails-3.0.x bundle install
19
+ # * script/with rails-3.0.x rake test
20
+
21
+ # == Constants ==============================================================
22
+
23
+ GEMFILE_DIR = File.expand_path('../test/gemfiles', File.dirname(__FILE__))
24
+ GEMFILE_ROOT = File.expand_path('../Gemfile', File.dirname(__FILE__))
25
+
26
+ # == Support Methods ========================================================
27
+
28
+ def dependencies(gemfile)
29
+ dependencies = { }
30
+
31
+ File.open(gemfile) do |f|
32
+ f.each do |line|
33
+ if (line.match(/\Agem\s+['"]bundler['"]\s*,\s*['"]([^'"]+)['"]/))
34
+ dependencies[:bundler] = $1
35
+ elsif (line.match(/\A\#\s*rubygems\s+(\S+)/))
36
+ dependencies[:rubygems] = $1
37
+ end
38
+ end
39
+ end
40
+
41
+ dependencies
42
+ end
43
+
44
+ def gemfile_list
45
+ Dir.entries(GEMFILE_DIR).reject do |name|
46
+ name[/\A\./] or name[/\.lock\z/]
47
+ end.collect do |name|
48
+ name.sub(/\AGemfile\./, '')
49
+ end
50
+ end
51
+
52
+ def with_variant(variant, &block)
53
+ case (variant)
54
+ when 'current'
55
+ if (ENV['BUNDLE_GEMFILE'])
56
+ yield(dependencies(ENV['BUNDLE_GEMFILE']))
57
+ else
58
+ yield(dependencies(GEMFILE_ROOT))
59
+ end
60
+ when 'each', 'all'
61
+ gemfile_list.each do |_variant|
62
+ with_variant(_variant, &block)
63
+ end
64
+ else
65
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile.%s' % variant, GEMFILE_DIR)
66
+
67
+ yield(dependencies(ENV['BUNDLE_GEMFILE']))
68
+ end
69
+ end
70
+
71
+ def shell(*args)
72
+ if (ENV['WITH_VERBOSE'])
73
+ puts args.join(' ')
74
+ end
75
+
76
+ unless (system(*args))
77
+ exit($?)
78
+ end
79
+ end
80
+
81
+ # == Main ===================================================================
82
+
83
+ variant = ARGV[0]
84
+
85
+ unless (variant)
86
+ puts "Usage: with <gemspec variant> <env|bootstrap|bundle|rake> ..."
87
+
88
+
89
+ puts
90
+ puts "Available variants:"
91
+ gemfile_list.each do |name|
92
+ puts name
93
+ end
94
+
95
+ exit(-1)
96
+ end
97
+
98
+ with_variant(variant) do |dependencies|
99
+ bundle_version_args = dependencies[:bundler] ? [ '_%s_' % dependencies[:bundler] ] : [ ]
100
+
101
+ case (ARGV[1])
102
+ when 'env'
103
+ puts 'BUNDLE_GEMFILE=%s' % ENV['BUNDLE_GEMFILE']
104
+ when 'bootstrap'
105
+ if (dependencies[:rubygems])
106
+ shell('gem', 'update', '--system', dependencies[:rubygems])
107
+ end
108
+ if (dependencies[:bundler])
109
+ shell('gem', 'install', 'bundler', '-v', dependencies[:bundler])
110
+ end
111
+ when 'bundle'
112
+ shell("bundle", *bundle_version_args, *ARGV.to_a[2, ARGV.length])
113
+ when 'rake'
114
+ shell("bundle", *bundle_version_args, "exec", "rake", *ARGV.to_a[2, ARGV.length])
115
+ end
116
+ end