postageapp 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +3 -0
  2. data/LICENSE +1 -1
  3. data/README.md +176 -0
  4. data/Rakefile +14 -12
  5. data/VERSION +1 -1
  6. data/generators/postageapp/postageapp_generator.rb +34 -0
  7. data/generators/postageapp/templates/initializer.rb +3 -0
  8. data/generators/postageapp/templates/postageapp_tasks.rake +78 -0
  9. data/lib/generators/postageapp/postageapp_generator.rb +27 -0
  10. data/lib/postageapp.rb +56 -0
  11. data/lib/postageapp/configuration.rb +91 -0
  12. data/lib/postageapp/failed_request.rb +64 -0
  13. data/lib/postageapp/logger.rb +16 -0
  14. data/lib/postageapp/mailer.rb +48 -0
  15. data/lib/postageapp/mailer/mailer_2.rb +92 -0
  16. data/lib/postageapp/mailer/mailer_3.rb +192 -0
  17. data/lib/postageapp/rails.rb +14 -0
  18. data/lib/postageapp/request.rb +87 -0
  19. data/lib/postageapp/response.rb +39 -0
  20. data/lib/postageapp/utils.rb +30 -0
  21. data/lib/postageapp/version.rb +7 -0
  22. data/postageapp.gemspec +61 -7
  23. data/test/configuration_test.rb +66 -0
  24. data/test/failed_request_test.rb +79 -0
  25. data/test/helper.rb +66 -0
  26. data/test/mailer/action_mailer_2/notifier.rb +64 -0
  27. data/test/mailer/action_mailer_2/notifier/with_body_and_attachment.erb +1 -0
  28. data/test/mailer/action_mailer_2/notifier/with_html_and_text_views.text.html.erb +1 -0
  29. data/test/mailer/action_mailer_2/notifier/with_html_and_text_views.text.plain.erb +1 -0
  30. data/test/mailer/action_mailer_2/notifier/with_simple_view.erb +1 -0
  31. data/test/mailer/action_mailer_2/notifier/with_text_only_view.text.plain.erb +1 -0
  32. data/test/mailer/action_mailer_3/notifier.rb +98 -0
  33. data/test/mailer/action_mailer_3/notifier/with_html_and_text_views.html.erb +1 -0
  34. data/test/mailer/action_mailer_3/notifier/with_html_and_text_views.text.erb +1 -0
  35. data/test/mailer/action_mailer_3/notifier/with_old_api.html.erb +1 -0
  36. data/test/mailer/action_mailer_3/notifier/with_old_api.text.erb +1 -0
  37. data/test/mailer/action_mailer_3/notifier/with_simple_view.erb +1 -0
  38. data/test/mailer/action_mailer_3/notifier/with_text_only_view.text.erb +1 -0
  39. data/test/mailer_2_test.rb +87 -0
  40. data/test/mailer_3_test.rb +104 -0
  41. data/test/mailer_helper_methods_test.rb +24 -0
  42. data/test/postageapp_test.rb +18 -0
  43. data/test/rails_initialization_test.rb +29 -0
  44. data/test/request_integration_test.rb +78 -0
  45. data/test/request_test.rb +81 -0
  46. data/test/response_test.rb +40 -0
  47. metadata +84 -9
  48. data/README.rdoc +0 -17
  49. data/test/test_postageapp.rb +0 -7
@@ -0,0 +1,14 @@
1
+ require 'postageapp'
2
+
3
+ module PostageApp::Rails
4
+
5
+ def self.initialize
6
+ PostageApp.configure do |config|
7
+ config.framework = "Rails #{::Rails.version}" if defined?(::Rails.version)
8
+ config.project_root = ::Rails.root if defined?(::Rails.root)
9
+ config.environment = ::Rails.env if defined?(::Rails.env)
10
+ end
11
+ end
12
+ end
13
+
14
+ PostageApp::Rails.initialize
@@ -0,0 +1,87 @@
1
+ class PostageApp::Request
2
+
3
+ API_VERSION = '1.0'
4
+
5
+ HEADERS = {
6
+ 'Content-type' => 'application/json',
7
+ 'Accept' => 'text/json, application/json'
8
+ }
9
+
10
+ # Unique ID of the request
11
+ attr_accessor :uid
12
+
13
+ # The API method being called (example: send_message)
14
+ # This controls the url of the request (example: https://api.postageapp.com/v.1.0/send_message.json)
15
+ attr_accessor :method
16
+
17
+ # A list of arguments in a Hash format passed along with the request
18
+ attr_accessor :arguments
19
+
20
+ def initialize(method, arguments = {})
21
+ @method = method
22
+ @uid = arguments.delete(:uid)
23
+ @arguments = arguments
24
+ end
25
+
26
+ # Skipping resend doesn't trigger PostageApp::FailedRequest.resend_all
27
+ # it's needed so the request being resend doesn't create duplicate queue
28
+ def send(skip_failed_requests_processing = false)
29
+ http = Net::HTTP::Proxy(
30
+ PostageApp.configuration.proxy_host,
31
+ PostageApp.configuration.proxy_port,
32
+ PostageApp.configuration.proxy_user,
33
+ PostageApp.configuration.proxy_pass
34
+ ).new(url.host, url.port)
35
+
36
+ http.read_timeout = PostageApp.configuration.http_read_timeout
37
+ http.open_timeout = PostageApp.configuration.http_open_timeout
38
+ http.use_ssl = PostageApp.configuration.secure?
39
+
40
+ PostageApp.logger.info(self)
41
+
42
+ http_response = begin
43
+ http.post(
44
+ url.path,
45
+ self.arguments_to_send.to_json,
46
+ HEADERS.merge('User-Agent' => "PostageApp-RubyGem #{PostageApp::VERSION} (Ruby #{RUBY_VERSION}, #{PostageApp.configuration.framework})")
47
+ )
48
+ rescue TimeoutError
49
+ nil
50
+ end
51
+
52
+ response = PostageApp::Response.new(http_response)
53
+
54
+ PostageApp.logger.info(response)
55
+
56
+ unless skip_failed_requests_processing
57
+ response.fail?? PostageApp::FailedRequest.store(self) : PostageApp::FailedRequest.resend_all
58
+ end
59
+
60
+ response
61
+ end
62
+
63
+ # URL of the where PostageApp::Request will be directed at
64
+ def url
65
+ URI.parse("#{PostageApp.configuration.url}/v.#{API_VERSION}/#{self.method}.json")
66
+ end
67
+
68
+ # Unique ID of the request
69
+ def uid(reload = false)
70
+ @uid = nil if reload
71
+ @uid ||= Digest::SHA1.hexdigest("#{Time.now.to_f}#{self.arguments}")
72
+ end
73
+
74
+ # Arguments need to be appended with some some stuff before it's ready to be send out
75
+ def arguments_to_send
76
+ hash = { 'uid' => self.uid, 'api_key' => PostageApp.configuration.api_key }
77
+
78
+ if !self.arguments.nil? && !self.arguments.empty?
79
+ if !PostageApp.configuration.recipient_override.nil? && self.method.to_sym == :send_message
80
+ self.arguments.merge!('recipient_override' => PostageApp.configuration.recipient_override)
81
+ end
82
+ hash.merge!('arguments' => self.arguments.stringify_keys!)
83
+ end
84
+ hash
85
+ end
86
+
87
+ end
@@ -0,0 +1,39 @@
1
+ class PostageApp::Response
2
+
3
+ # The UID should match the Request's UID. If Request didn't provide with one
4
+ # PostageApp service should generate it for the Response
5
+ attr_reader :uid
6
+
7
+ # The status of the response in string format (like: ok, bad_request)
8
+ # Will be set to +fail+ if Request times out
9
+ attr_reader :status
10
+
11
+ # The message of the response. Could be used as an error explanation.
12
+ attr_reader :message
13
+
14
+ # The data payload of the response. This is usually the return value of the
15
+ # request we're looking for
16
+ attr_reader :data
17
+
18
+ # Takes in Net::HTTPResponse object as the attribute.
19
+ # If something goes wrong Response will be thought of as failed
20
+ def initialize(http_response)
21
+ hash = JSON::parse(http_response.body)
22
+ @status = hash['response']['status']
23
+ @uid = hash['response']['uid']
24
+ @message = hash['response']['message']
25
+ @data = hash['data']
26
+ rescue
27
+ @status = 'fail'
28
+ end
29
+
30
+ # Little helper that checks for the Response status
31
+ # => @response.ok?
32
+ # >> true
33
+ # => @response.fail?
34
+ # >> false
35
+ def method_missing(method)
36
+ /.*?\?$/.match(method.to_s) ? "#{self.status}?" == method.to_s : super(method)
37
+ end
38
+
39
+ end
@@ -0,0 +1,30 @@
1
+ class Hash
2
+
3
+ # Example usage:
4
+ # @hash.dig(:k1) # same as @hash[:k1]
5
+ # @hash.dig(:k1, :k2) # same as @hash[:k1] && @hash[:k1][:k2]
6
+ # @hash.dig(:k1, :k2, k3) # same as @hash[:k1] && @hash[:k1][:k2] && @hash[:k1][:k2][:k3]
7
+ def dig(*path)
8
+ path.inject(self) do |location, key|
9
+ location.respond_to?(:keys) ? location[key] : nil
10
+ end
11
+ end
12
+
13
+ # Destructively convert all keys to strings.
14
+ def stringify_keys!
15
+ keys.each do |key|
16
+ self[key.to_s] = delete(key)
17
+ end
18
+ self
19
+ end
20
+ end
21
+
22
+ class Net::HTTP
23
+ # Getting rid of the 'warning: peer certificate won't be verified in this SSL session'
24
+ alias_method :old_initialize, :initialize
25
+ def initialize(*args)
26
+ old_initialize(*args)
27
+ @ssl_context = OpenSSL::SSL::SSLContext.new
28
+ @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ module PostageApp
2
+ VERSION = begin
3
+ IO.read(File.join(File.dirname(__FILE__), '/../../VERSION')).chomp
4
+ rescue
5
+ 'UNKNOWN'
6
+ end
7
+ end
@@ -5,28 +5,65 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{postageapp}
8
- s.version = "0.0.0"
8
+ s.version = "1.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Oleg Khabarov, The Working Group Inc"]
12
- s.date = %q{2010-06-10}
12
+ s.date = %q{2010-07-23}
13
13
  s.description = %q{Gem that interfaces with PostageApp.com service to send emails from web apps}
14
14
  s.email = %q{oleg@twg.ca}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
21
  ".gitignore",
22
22
  "LICENSE",
23
- "README.rdoc",
23
+ "README.md",
24
24
  "Rakefile",
25
25
  "VERSION",
26
+ "generators/postageapp/postageapp_generator.rb",
27
+ "generators/postageapp/templates/initializer.rb",
28
+ "generators/postageapp/templates/postageapp_tasks.rake",
29
+ "lib/generators/postageapp/postageapp_generator.rb",
26
30
  "lib/postageapp.rb",
31
+ "lib/postageapp/configuration.rb",
32
+ "lib/postageapp/failed_request.rb",
33
+ "lib/postageapp/logger.rb",
34
+ "lib/postageapp/mailer.rb",
35
+ "lib/postageapp/mailer/mailer_2.rb",
36
+ "lib/postageapp/mailer/mailer_3.rb",
37
+ "lib/postageapp/rails.rb",
38
+ "lib/postageapp/request.rb",
39
+ "lib/postageapp/response.rb",
40
+ "lib/postageapp/utils.rb",
41
+ "lib/postageapp/version.rb",
27
42
  "postageapp.gemspec",
43
+ "test/configuration_test.rb",
44
+ "test/failed_request_test.rb",
28
45
  "test/helper.rb",
29
- "test/test_postageapp.rb"
46
+ "test/mailer/action_mailer_2/notifier.rb",
47
+ "test/mailer/action_mailer_2/notifier/with_body_and_attachment.erb",
48
+ "test/mailer/action_mailer_2/notifier/with_html_and_text_views.text.html.erb",
49
+ "test/mailer/action_mailer_2/notifier/with_html_and_text_views.text.plain.erb",
50
+ "test/mailer/action_mailer_2/notifier/with_simple_view.erb",
51
+ "test/mailer/action_mailer_2/notifier/with_text_only_view.text.plain.erb",
52
+ "test/mailer/action_mailer_3/notifier.rb",
53
+ "test/mailer/action_mailer_3/notifier/with_html_and_text_views.html.erb",
54
+ "test/mailer/action_mailer_3/notifier/with_html_and_text_views.text.erb",
55
+ "test/mailer/action_mailer_3/notifier/with_old_api.html.erb",
56
+ "test/mailer/action_mailer_3/notifier/with_old_api.text.erb",
57
+ "test/mailer/action_mailer_3/notifier/with_simple_view.erb",
58
+ "test/mailer/action_mailer_3/notifier/with_text_only_view.text.erb",
59
+ "test/mailer_2_test.rb",
60
+ "test/mailer_3_test.rb",
61
+ "test/mailer_helper_methods_test.rb",
62
+ "test/postageapp_test.rb",
63
+ "test/rails_initialization_test.rb",
64
+ "test/request_integration_test.rb",
65
+ "test/request_test.rb",
66
+ "test/response_test.rb"
30
67
  ]
31
68
  s.homepage = %q{http://github.com/theworkinggroup/postageapp-gem}
32
69
  s.rdoc_options = ["--charset=UTF-8"]
@@ -34,8 +71,19 @@ Gem::Specification.new do |s|
34
71
  s.rubygems_version = %q{1.3.6}
35
72
  s.summary = %q{Easier way to send email from web apps}
36
73
  s.test_files = [
37
- "test/helper.rb",
38
- "test/test_postageapp.rb"
74
+ "test/configuration_test.rb",
75
+ "test/failed_request_test.rb",
76
+ "test/helper.rb",
77
+ "test/mailer/action_mailer_2/notifier.rb",
78
+ "test/mailer/action_mailer_3/notifier.rb",
79
+ "test/mailer_2_test.rb",
80
+ "test/mailer_3_test.rb",
81
+ "test/mailer_helper_methods_test.rb",
82
+ "test/postageapp_test.rb",
83
+ "test/rails_initialization_test.rb",
84
+ "test/request_integration_test.rb",
85
+ "test/request_test.rb",
86
+ "test/response_test.rb"
39
87
  ]
40
88
 
41
89
  if s.respond_to? :specification_version then
@@ -43,9 +91,15 @@ Gem::Specification.new do |s|
43
91
  s.specification_version = 3
44
92
 
45
93
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
94
+ s.add_runtime_dependency(%q<json>, ["= 1.2.4"])
95
+ s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
46
96
  else
97
+ s.add_dependency(%q<json>, ["= 1.2.4"])
98
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
47
99
  end
48
100
  else
101
+ s.add_dependency(%q<json>, ["= 1.2.4"])
102
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
49
103
  end
50
104
  end
51
105
 
@@ -0,0 +1,66 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class ConfigurationTest < Test::Unit::TestCase
4
+
5
+ def test_intitialization_defaults
6
+ config = PostageApp::Configuration.new
7
+
8
+ assert_equal true, config.secure
9
+ assert_equal nil, config.api_key
10
+ assert_equal 'https', config.protocol
11
+ assert_equal 'api.postageapp.com', config.host
12
+ assert_equal 443, config.port
13
+ assert_equal nil, config.proxy_host
14
+ assert_equal nil, config.proxy_port
15
+ assert_equal nil, config.proxy_user
16
+ assert_equal nil, config.proxy_pass
17
+ assert_equal 5, config.http_open_timeout
18
+ assert_equal 10, config.http_read_timeout
19
+ assert_equal nil, config.recipient_override
20
+ assert_equal %w( send_message ), config.requests_to_resend
21
+ assert_equal nil, config.project_root
22
+ assert_equal 'production', config.environment
23
+ assert_equal nil, config.logger
24
+ assert_equal 'undefined framework', config.framework
25
+ end
26
+
27
+ def test_initialization_overrides
28
+ config = PostageApp::Configuration.new
29
+
30
+ config.protocol = 'http'
31
+ config.port = 999
32
+
33
+ assert_equal 'http', config.protocol
34
+ assert_equal 999, config.port
35
+ end
36
+
37
+ def test_intitialization_for_secure
38
+ config = PostageApp::Configuration.new
39
+
40
+ config.secure = true
41
+ assert_equal true, config.secure
42
+ assert_equal 'https', config.protocol
43
+ assert_equal 443, config.port
44
+
45
+ assert config.secure?
46
+ end
47
+
48
+ def test_intialization_for_insecure
49
+ config = PostageApp::Configuration.new
50
+
51
+ config.secure = false
52
+ assert_equal false, config.secure
53
+ assert_equal 'http', config.protocol
54
+ assert_equal 80, config.port
55
+
56
+ assert !config.secure?
57
+ end
58
+
59
+ def test_method_url
60
+ config = PostageApp::Configuration.new
61
+
62
+ config.host = 'api.postageapp.com'
63
+ assert_equal 'https://api.postageapp.com:443', config.url
64
+ end
65
+
66
+ end
@@ -0,0 +1,79 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class FailedRequestTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ super
7
+ PostageApp.configuration.project_root = File.expand_path('../', __FILE__)
8
+ end
9
+
10
+ def test_store_and_initialize
11
+ assert_match /.*?\/tmp\/postageapp_failed_requests/, PostageApp::FailedRequest.store_path
12
+
13
+ request = PostageApp::Request.new(:send_message, {
14
+ :headers => { 'from' => 'sender@test.test',
15
+ 'subject' => 'Test Message'},
16
+ :recipients => 'test@test.test',
17
+ :content => {
18
+ 'text/plain' => 'text content',
19
+ 'text/html' => 'html content'
20
+ }
21
+ })
22
+ assert PostageApp::FailedRequest.store(request)
23
+ file_path = File.join(PostageApp::FailedRequest.store_path, request.uid)
24
+ assert File.exists?(file_path)
25
+
26
+ stored_request = PostageApp::FailedRequest.initialize_request(request.uid)
27
+ assert stored_request.is_a?(PostageApp::Request)
28
+ assert_equal request.url, stored_request.url
29
+ assert_equal request.uid, stored_request.uid
30
+ assert_equal request.arguments_to_send, stored_request.arguments_to_send
31
+ end
32
+
33
+ def test_initialize_request_when_not_found
34
+ assert !PostageApp::FailedRequest.initialize_request('not_there')
35
+ end
36
+
37
+ def test_store_for_wrong_call_type
38
+ request = PostageApp::Request.new(:get_project_info)
39
+ assert !PostageApp::FailedRequest.store(request)
40
+ end
41
+
42
+ def test_store_with_no_file_path_defined
43
+ PostageApp.configuration.project_root = nil
44
+ assert !PostageApp::FailedRequest.store_path
45
+ assert !PostageApp::FailedRequest.store('something')
46
+ end
47
+
48
+ def test_resend_all
49
+ mock_failed_send
50
+
51
+ request = PostageApp::Request.new(:send_message, {
52
+ :headers => { 'from' => 'sender@test.test',
53
+ 'subject' => 'Test Message'},
54
+ :recipients => 'test@test.test',
55
+ :content => {
56
+ 'text/plain' => 'text content',
57
+ 'text/html' => 'html content'
58
+ }
59
+ })
60
+ response = request.send
61
+ assert response.fail?
62
+ file_path = File.join(PostageApp::FailedRequest.store_path, request.uid)
63
+ assert File.exists?(file_path)
64
+
65
+ mock_successful_send
66
+
67
+ request = PostageApp::Request.new(:get_project_info)
68
+
69
+ message_receipt_response = stub(:ok? => false, :not_found? => true)
70
+ message_receipt_request = stub(:send => message_receipt_response)
71
+ PostageApp::Request.stubs(:new).with{|a,b| a == :get_message_receipt}.returns(message_receipt_request)
72
+
73
+ response = request.send
74
+ assert response.ok?
75
+
76
+ assert !File.exists?(file_path)
77
+ end
78
+
79
+ end
@@ -3,7 +3,73 @@ require 'test/unit'
3
3
 
4
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
6
7
  require 'postageapp'
8
+ require 'postageapp/mailer'
9
+
10
+ begin require 'redgreen' unless ENV['TM_FILEPATH']; rescue LoadError; end
11
+ require 'mocha'
7
12
 
8
13
  class Test::Unit::TestCase
14
+
15
+ def setup
16
+ # resetting to default configuration
17
+ PostageApp.configure do |config|
18
+ config.api_key = '1234567890abcdef'
19
+ config.secure = true
20
+ config.protocol = 'https'
21
+ config.host = 'api.postageapp.com'
22
+ config.port = 443
23
+ config.proxy_host = nil
24
+ config.proxy_port = nil
25
+ config.proxy_user = nil
26
+ config.proxy_pass = nil
27
+ config.http_open_timeout = 5
28
+ config.http_read_timeout = 10
29
+ config.recipient_override = nil
30
+ config.requests_to_resend = %w( send_message )
31
+ config.project_root = File.expand_path('../', __FILE__)
32
+ config.environment = 'production'
33
+ config.logger = nil
34
+ config.framework = 'undefined framework'
35
+ end
36
+ end
37
+
38
+ def mock_successful_send
39
+ Net::HTTP.any_instance.stubs(:post).returns(Net::HTTPResponse.new(nil, nil, nil))
40
+ Net::HTTPResponse.any_instance.stubs(:body).returns({
41
+ :response => {
42
+ :uid => 'sha1hashuid23456789012345678901234567890',
43
+ :status => 'ok'
44
+ },
45
+ :data => {
46
+ :message => { :id => 999 }
47
+ }
48
+ }.to_json)
49
+ end
50
+
51
+ def mock_failed_send
52
+ Net::HTTP.any_instance.stubs(:post).returns(nil)
53
+ end
54
+
55
+ end
56
+
57
+ # Setting up constants just for the duration of the test
58
+ module ConstantDefinitions
59
+
60
+ def setup
61
+ @defined_constants = []
62
+ end
63
+
64
+ def teardown
65
+ @defined_constants.each do |constant|
66
+ Object.__send__(:remove_const, constant)
67
+ end
68
+ end
69
+
70
+ def define_constant(name, value)
71
+ Object.const_set(name, value)
72
+ @defined_constants << name
73
+ end
74
+
9
75
  end