postageapp 1.2.5 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +10 -30
  4. data/{LICENSE → LICENSE.md} +1 -1
  5. data/README.md +118 -68
  6. data/Rakefile +15 -4
  7. data/VERSION +1 -0
  8. data/app/ingresses/action_mailbox/ingresses/postage_app.rb +2 -0
  9. data/app/ingresses/action_mailbox/ingresses/postage_app/inbound_emails_controller.rb +50 -0
  10. data/config/routes.rb +6 -0
  11. data/doc/RAILS2.md +54 -0
  12. data/doc/RAILS3.md +15 -0
  13. data/exe/postageapp +37 -0
  14. data/generators/postageapp/templates/postageapp_tasks.rake +25 -8
  15. data/lib/generators/postageapp/postageapp_generator.rb +9 -6
  16. data/lib/postageapp.rb +59 -30
  17. data/lib/postageapp/cli.rb +14 -0
  18. data/lib/postageapp/cli/command.rb +110 -0
  19. data/lib/postageapp/cli/command/config.rb +74 -0
  20. data/lib/postageapp/cli/command/create_mailbox.rb +21 -0
  21. data/lib/postageapp/cli/command/env.rb +58 -0
  22. data/lib/postageapp/cli/command/get_project_info.rb +3 -0
  23. data/lib/postageapp/configuration.rb +267 -63
  24. data/lib/postageapp/diagnostics.rb +30 -0
  25. data/lib/postageapp/engine.rb +9 -0
  26. data/lib/postageapp/env.rb +9 -0
  27. data/lib/postageapp/failed_request.rb +2 -0
  28. data/lib/postageapp/http.rb +32 -0
  29. data/lib/postageapp/logger.rb +2 -0
  30. data/lib/postageapp/mail.rb +1 -1
  31. data/lib/postageapp/mailer.rb +2 -11
  32. data/lib/postageapp/mailer/mailer_4.rb +29 -15
  33. data/lib/postageapp/rails/railtie.rb +1 -3
  34. data/lib/postageapp/request.rb +27 -11
  35. data/lib/postageapp/response.rb +22 -8
  36. data/lib/postageapp/utils.rb +0 -11
  37. data/log/.gitignore +1 -0
  38. data/postageapp.gemspec +16 -17
  39. data/script/with +3 -3
  40. data/test/gemfiles/Gemfile.rails-2.3.x +1 -1
  41. data/test/gemfiles/Gemfile.rails-3.0.x +1 -1
  42. data/test/gemfiles/Gemfile.rails-3.1.x +1 -1
  43. data/test/gemfiles/Gemfile.rails-3.2.x +1 -1
  44. data/test/gemfiles/Gemfile.rails-4.0.x +1 -1
  45. data/test/gemfiles/Gemfile.rails-4.1.x +1 -1
  46. data/test/gemfiles/Gemfile.rails-4.2.x +1 -2
  47. data/test/gemfiles/Gemfile.rails-5.0.x +12 -0
  48. data/test/gemfiles/Gemfile.rails-5.2.x +12 -0
  49. data/test/gemfiles/Gemfile.rails-6.0.x +12 -0
  50. data/test/gemfiles/Gemfile.rails-6.1.x +12 -0
  51. data/test/gemfiles/Gemfile.ruby +2 -3
  52. data/test/helper.rb +6 -17
  53. data/test/log/.gitignore +1 -0
  54. data/test/mailer/action_mailer_3/notifier.rb +10 -10
  55. data/test/tmp/.gitignore +1 -0
  56. data/test/travis_test.rb +58 -40
  57. data/test/{configuration_test.rb → unit/configuration_test.rb} +35 -22
  58. data/test/{failed_request_test.rb → unit/failed_request_test.rb} +6 -6
  59. data/test/{live_test.rb → unit/live_test.rb} +33 -43
  60. data/test/{mail_delivery_method_test.rb → unit/mail_delivery_method_test.rb} +1 -1
  61. data/test/{mailer_4_test.rb → unit/mailer_4_test.rb} +2 -2
  62. data/test/{mailer_helper_methods_test.rb → unit/mailer_helper_methods_test.rb} +4 -4
  63. data/test/{postageapp_test.rb → unit/postageapp_test.rb} +10 -1
  64. data/test/{rails_initialization_test.rb → unit/rails_initialization_test.rb} +2 -2
  65. data/test/{request_test.rb → unit/request_test.rb} +24 -23
  66. data/test/{response_test.rb → unit/response_test.rb} +4 -4
  67. data/test/unit/tmp/.gitignore +1 -0
  68. data/tmp/.gitignore +1 -0
  69. metadata +60 -68
  70. data/lib/postageapp/mailer/mailer_2.rb +0 -140
  71. data/lib/postageapp/mailer/mailer_3.rb +0 -190
  72. data/lib/postageapp/version.rb +0 -3
  73. data/test/mailer/action_mailer_2/notifier.rb +0 -76
  74. data/test/mailer/action_mailer_2/notifier/with_body_and_attachment.erb +0 -1
  75. data/test/mailer/action_mailer_2/notifier/with_custom_postage_variables.text.html.erb +0 -1
  76. data/test/mailer/action_mailer_2/notifier/with_custom_postage_variables.text.plain.erb +0 -1
  77. data/test/mailer/action_mailer_2/notifier/with_html_and_text_views.text.html.erb +0 -1
  78. data/test/mailer/action_mailer_2/notifier/with_html_and_text_views.text.plain.erb +0 -1
  79. data/test/mailer/action_mailer_2/notifier/with_simple_view.erb +0 -1
  80. data/test/mailer/action_mailer_2/notifier/with_text_only_view.text.plain.erb +0 -1
  81. data/test/mailer_2_test.rb +0 -95
  82. data/test/mailer_3_test.rb +0 -118
@@ -0,0 +1,74 @@
1
+ PostageApp::CLI::Command.define do
2
+ argument :'no-header',
3
+ optional: true,
4
+ boolean: true,
5
+ desc: 'An identifier to refer to this mailbox on subsequent API calls'
6
+
7
+ argument :markdown,
8
+ optional: true,
9
+ boolean: true,
10
+ desc: 'Emit markdown formatted description of variables'
11
+
12
+ perform do |arguments|
13
+ if (arguments[:markdown])
14
+ PostageApp::Configuration.params.each do |param, config|
15
+ case (default = config[:default])
16
+ when Proc
17
+ default = default.call
18
+ end
19
+
20
+ puts '* `%s`: %s (%s)' % [
21
+ param,
22
+ config[:desc],
23
+ case (config[:required])
24
+ when String
25
+ 'required %s' % config[:required]
26
+ when true
27
+ 'required'
28
+ else
29
+ default ? 'default: `%s`' % default : 'optional'
30
+ end
31
+ ]
32
+
33
+ config[:aliases]&.each do |param_alias|
34
+ puts '* `%s`: Alias for `%s`' % [
35
+ param_alias,
36
+ param
37
+ ]
38
+ end
39
+ end
40
+ else
41
+ unless (arguments[:'no-header'])
42
+ puts '%-40s %s' % [ 'Variable', 'Description' ]
43
+ puts '-' * 78
44
+ end
45
+
46
+ PostageApp::Configuration.params.each do |param, config|
47
+ case (default = config[:default])
48
+ when Proc
49
+ default = default.call
50
+ end
51
+
52
+ puts '%-40s %s (%s)' % [
53
+ param,
54
+ config[:desc],
55
+ case (config[:required])
56
+ when String
57
+ 'required %s' % config[:required]
58
+ when true
59
+ 'required'
60
+ else
61
+ default ? 'default: %s' % default : 'optional'
62
+ end
63
+ ]
64
+
65
+ config[:aliases]&.each do |param_alias|
66
+ puts '%-40s Alias for %s' % [
67
+ param_alias,
68
+ param
69
+ ]
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,21 @@
1
+ PostageApp::CLI::Command.define do
2
+ api_key :account
3
+
4
+ argument :uid,
5
+ optional: true,
6
+ desc: 'An identifier to refer to this mailbox on subsequent API calls'
7
+ argument :label,
8
+ optional: true,
9
+ desc: 'A descriptive name for this mailbox'
10
+ argument :host,
11
+ desc: 'IMAP server hostname'
12
+ argument :port,
13
+ optional: true,
14
+ desc: 'IMAP server port (default 993)'
15
+ argument :username,
16
+ desc: 'Username/email-address used to authenticate with the IMAP server'
17
+ argument :password,
18
+ desc: 'Password used to authenticate with the IMAP server'
19
+ argument :postback_url,
20
+ desc: 'The URL to post received email content to'
21
+ end
@@ -0,0 +1,58 @@
1
+ PostageApp::CLI::Command.define do
2
+ argument :'no-header',
3
+ optional: true,
4
+ boolean: true,
5
+ desc: 'Suppress display of header'
6
+
7
+ argument :markdown,
8
+ optional: true,
9
+ boolean: true,
10
+ desc: 'Emit markdown formatted description of variables'
11
+
12
+ perform do |arguments|
13
+ if (arguments[:markdown])
14
+ PostageApp::Configuration.params.each do |param, config|
15
+ config[:env_vars]&.each_with_index do |var, i|
16
+ case (i)
17
+ when 0
18
+ case (default = config[:default])
19
+ when Proc
20
+ default = default.call
21
+ end
22
+
23
+ puts '* `%s`: %s (%s)' % [
24
+ var,
25
+ config[:desc],
26
+ case (config[:required])
27
+ when String
28
+ 'required %s' % config[:required]
29
+ when true
30
+ 'required'
31
+ else
32
+ default ? 'default: `%s`' % default : 'optional'
33
+ end
34
+ ]
35
+ else
36
+ puts '* `%s`: Alias for `%s`' % [
37
+ var,
38
+ config[:env_vars][0]
39
+ ]
40
+ end
41
+ end
42
+ end
43
+ else
44
+ unless (arguments[:'no-header'])
45
+ puts '%-40s %s' % [ 'Variable', 'Setting' ]
46
+ puts '-' * 78
47
+ end
48
+
49
+ PostageApp::Configuration.params.each do |param, config|
50
+ config[:env_vars]&.each do |var|
51
+ puts '%-40s %s' % [
52
+ var, ENV[var]
53
+ ]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ PostageApp::CLI::Command.define do
2
+ # No arguments required for this command
3
+ end
@@ -32,90 +32,294 @@
32
32
  # -------------
33
33
  # :proxy_host - Proxy server hostname
34
34
  # :proxy_port - Proxy server port
35
- # :proxy_user - Proxy server username
36
- # :proxy_pass - Proxy server password
35
+ # :proxy_username - Proxy server username
36
+ # :proxy_password - Proxy server password
37
37
 
38
38
  # Advanced Options
39
39
  # ----------------
40
40
  # :port - The port to make HTTP/HTTPS requests (default based on secure option)
41
- # :protocol - Set to either `http` or `https` (default based on secure option)
41
+ # :scheme - Set to either `http` or `https` (default based on secure option)
42
42
  # :requests_to_resend - List of API calls that should be replayed if they fail.
43
43
  # (default: send_message)
44
44
 
45
45
  class PostageApp::Configuration
46
- attr_accessor :secure
47
- attr_writer :protocol
48
- attr_accessor :host
49
- attr_writer :port
50
- attr_accessor :proxy_host
51
- attr_accessor :proxy_port
52
- attr_accessor :proxy_user
53
- attr_accessor :proxy_pass
54
- attr_accessor :http_open_timeout
55
- attr_accessor :http_read_timeout
56
- attr_accessor :recipient_override
57
- attr_accessor :requests_to_resend
58
- attr_accessor :project_root
59
- attr_accessor :framework
60
- attr_accessor :environment
61
- attr_accessor :logger
62
-
63
- def initialize
64
- @secure = true
65
- @host = 'api.postageapp.com'
46
+ # == Constants ============================================================
47
+
48
+ SOCKS5_PORT_DEFAULT = 1080
49
+ HTTP_PORT_DEFAULT = 80
50
+ HTTPS_PORT_DEFAULT = 443
51
+
52
+ SCHEME_FOR_SECURE = {
53
+ true => 'https'.freeze,
54
+ false => 'http'.freeze
55
+ }.freeze
56
+
57
+ CONFIG_PARAMS = {
58
+ api_key: {
59
+ default: nil,
60
+ desc: 'Project API key to use',
61
+ required: 'for project API functions'
62
+ },
63
+ account_api_key: {
64
+ default: nil,
65
+ desc: 'Account API key to use',
66
+ required: 'for account API functions'
67
+ },
68
+ postback_secret: {
69
+ default: nil,
70
+ desc: 'Secret to use for validating ActionMailbox requests'
71
+ },
72
+ project_root: {
73
+ default: -> {
74
+ if (defined?(Rails) and Rails.respond_to?(:root))
75
+ Rails.root
76
+ else
77
+ Dir.pwd
78
+ end
79
+ },
80
+ desc: 'Project root for logging purposes'
81
+ },
82
+ recipient_override: {
83
+ default: nil,
84
+ interrogator: true,
85
+ desc: 'Override sender on `send_message` calls'
86
+ },
87
+ logger: {
88
+ default: nil,
89
+ env: false,
90
+ desc: 'Logger instance to use'
91
+ },
92
+ secure: {
93
+ default: true,
94
+ interrogator: true,
95
+ env: false,
96
+ after_set: -> (config) {
97
+ if (config.secure?)
98
+ config.protocol = 'https'
99
+ if (config.port == 80)
100
+ config.port = 443
101
+ end
102
+ else
103
+ config.protocol = 'http'
104
+ if (config.port == 443)
105
+ config.port = 80
106
+ end
107
+ end
108
+ },
109
+ desc: 'Enable verifying TLS connections'
110
+ },
111
+ verify_tls: {
112
+ default: true,
113
+ aliases: [ :verify_certificate ],
114
+ interrogator: true,
115
+ parse: -> (v) {
116
+ case (v)
117
+ when 'true', 'yes', 'on'
118
+ true
119
+ when String
120
+ v.to_i != 0
121
+ else
122
+ !!v
123
+ end
124
+ },
125
+ desc: 'Enable TLS certificate verification'
126
+ },
127
+ host: {
128
+ default: 'api.postageapp.com'.freeze,
129
+ desc: 'API host to contact'
130
+ },
131
+ port: {
132
+ default: 443,
133
+ desc: 'API port to contact'
134
+ },
135
+ scheme: {
136
+ default: 'https'.freeze,
137
+ aliases: [ :protocol ],
138
+ desc: 'HTTP scheme to use'
139
+ },
140
+ proxy_username: {
141
+ default: nil,
142
+ aliases: [ :proxy_user ],
143
+ desc: 'SOCKS5 proxy username'
144
+ },
145
+ proxy_password: {
146
+ default: nil,
147
+ aliases: [ :proxy_pass ],
148
+ desc: 'SOCKS5 proxy password'
149
+ },
150
+ proxy_host: {
151
+ default: nil,
152
+ desc: 'SOCKS5 proxy host'
153
+ },
154
+ proxy_port: {
155
+ default: 1080,
156
+ parse: -> (v) { v.to_i },
157
+ desc: 'SOCKS5 proxy port'
158
+ },
159
+ open_timeout: {
160
+ default: 5,
161
+ aliases: [ :http_open_timeout ],
162
+ parse: -> (v) { v.to_i },
163
+ desc: 'Timeout in seconds when initiating requests'
164
+ },
165
+ read_timeout: {
166
+ default: 10,
167
+ aliases: [ :http_read_timeout ],
168
+ parse: -> (v) { v.to_i },
169
+ desc: 'Timeout in seconds when awaiting responses'
170
+ },
171
+ retry_methods: {
172
+ default: %w[ send_message ].freeze,
173
+ aliases: [ :requests_to_resend ],
174
+ parse: -> (v) {
175
+ case (v)
176
+ when String
177
+ v.split(/\s*(?:,|\s)\s*/).grep(/\S/)
178
+ else
179
+ v
180
+ end
181
+ },
182
+ desc: 'Which API calls to retry, comma and/or space separated'
183
+ },
184
+ framework: {
185
+ default: -> {
186
+ if (defined?(Rails) and Rails.respond_to?(:version))
187
+ 'Ruby %s / Ruby on Rails %s' % [
188
+ RUBY_VERSION,
189
+ Rails.version
190
+ ]
191
+ else
192
+ 'Ruby %s' % RUBY_VERSION
193
+ end
194
+ },
195
+ desc: 'Framework used'
196
+ },
197
+ environment: {
198
+ default: 'production',
199
+ desc: 'Environment to use'
200
+ }
201
+ }.freeze
202
+
203
+ # == Properties ===========================================================
204
+
205
+ CONFIG_PARAMS.each do |param, config|
206
+ attr_reader param
207
+
208
+ ivar = config[:ivar] ||= :"@#{param}"
209
+ mutator_method = :"#{param}="
210
+ config[:sources] = [ param ]
211
+ after_set = config[:after_set]
212
+
213
+ if (parser = config[:parse])
214
+ define_method(mutator_method) do |v|
215
+ instance_variable_set(ivar, parser.call(v))
216
+ end
217
+ else
218
+ define_method(mutator_method) do |v|
219
+ instance_variable_set(ivar, v)
220
+
221
+ after_set and after_set[self]
222
+ end
223
+ end
224
+
225
+ interrogator_method = nil
226
+
227
+ if (config[:interrogator])
228
+ interrogator_method = :"#{param}?"
229
+ define_method(interrogator_method) do
230
+ !!instance_variable_get(ivar)
231
+ end
232
+ end
233
+
234
+ if (param_aliases = config[:aliases])
235
+ param_aliases.each do |param_alias|
236
+ config[:sources] << param_alias
66
237
 
67
- @http_open_timeout = 5
68
- @http_read_timeout = 10
238
+ alias_method param_alias, param
239
+ alias_method :"#{param_alias}=", mutator_method
69
240
 
70
- @requests_to_resend = %w[ send_message ]
241
+ if (config[:interrogator])
242
+ alias_method :"#{param_alias}?", interrogator_method
243
+ end
244
+ end
245
+ end
71
246
 
72
- @framework = 'Ruby'
247
+ unless (config[:env] === false)
248
+ config[:env_vars] = config[:sources].map do |source|
249
+ 'POSTAGEAPP_' + source.to_s.upcase
250
+ end
251
+ end
73
252
 
74
- @environment = 'production'
253
+ # config[:getters] = config[:sources].map do |source|
254
+ # -> (credentials) { credentials[:source] }
255
+ # end + config[:env_vars].map do |var|
256
+ # -> (_) { ENV[var] }
257
+ # end
75
258
  end
76
-
77
- alias_method :secure?, :secure
78
-
79
- # Assign which API key is used to make API calls. Can also be specified
80
- # using the `POSTAGEAPP_API_KEY` environment variable.
81
- def api_key=(key)
82
- @api_key = key
259
+
260
+ # == Class Methods ========================================================
261
+
262
+ def self.params
263
+ CONFIG_PARAMS
83
264
  end
84
-
85
- # Returns the API key used to make API calls. Can be specified as the
86
- # `POSTAGEAPP_API_KEY` environment variable.
87
- def api_key
88
- @api_key ||= ENV['POSTAGEAPP_API_KEY']
265
+
266
+ # == Instance Methods =====================================================
267
+
268
+ def initialize
269
+ credentials = self.rails_credentials
270
+
271
+ CONFIG_PARAMS.each do |param, config|
272
+ value = (
273
+ config[:sources]&.map { |s| credentials[s] }&.compact&.first ||
274
+ config[:env_vars]&.map { |v| ENV[v] }&.compact&.first
275
+ )
276
+
277
+ if (value)
278
+ if (config[:parse])
279
+ instance_variable_set(config[:ivar], config[:parse].call(value))
280
+ else
281
+ instance_variable_set(config[:ivar], value)
282
+ end
283
+ else
284
+ case (config[:default])
285
+ when Proc
286
+ instance_variable_set(config[:ivar], config[:default].call)
287
+ else
288
+ instance_variable_set(config[:ivar], config[:default])
289
+ end
290
+ end
291
+ end
89
292
  end
90
-
91
- # Returns the HTTP protocol used to make API calls
92
- def protocol
93
- @protocol ||= (secure? ? 'https' : 'http')
293
+
294
+ # Returns true if the port used for the API is the default port, otherwise
295
+ # false. 80 for HTTP, 443 for HTTPS.
296
+ def port_default?
297
+ self.port == (self.secure? ? HTTPS_PORT_DEFAULT : HTTP_PORT_DEFAULT)
94
298
  end
95
-
96
- # Returns the port used to make API calls
97
- def port
98
- @port ||= (secure? ? 443 : 80)
299
+
300
+ # Returns true if a proxy is defined, otherwise false.
301
+ def proxy?
302
+ self.proxy_host and self.proxy_host.match(/\A\S+\z/)
99
303
  end
100
-
304
+
101
305
  # Returns the endpoint URL to make API calls
102
306
  def url
103
- "#{self.protocol}://#{self.host}:#{self.port}"
307
+ '%s://%s%s' % [
308
+ self.scheme,
309
+ self.host,
310
+ self.port_default? ? '' : (':%d' % self.port)
311
+ ]
104
312
  end
105
313
 
106
- # Returns a properly configured Net::HTTP connection
314
+ # Returns a connection aimed at the API endpoint
107
315
  def http
108
- http = Net::HTTP::Proxy(
109
- self.proxy_host,
110
- self.proxy_port,
111
- self.proxy_user,
112
- self.proxy_pass
113
- ).new(self.host, self.port)
114
-
115
- http.read_timeout = self.http_read_timeout
116
- http.open_timeout = self.http_open_timeout
117
- http.use_ssl = self.secure?
118
-
119
- http
316
+ PostageApp::HTTP.connect(self)
317
+ end
318
+
319
+ protected
320
+ def rails_credentials
321
+ if (PostageApp::Env.rails_with_encrypted_credentials?)
322
+ Rails.application.credentials.postageapp
323
+ end or { }
120
324
  end
121
325
  end