rubymail 0.11

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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +64 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +201 -0
  5. data/README.md +2 -0
  6. data/Rakefile +1 -0
  7. data/lib/multimap/.gitignore +4 -0
  8. data/lib/multimap/LICENSE +20 -0
  9. data/lib/multimap/README.rdoc +16 -0
  10. data/lib/multimap/Rakefile +34 -0
  11. data/lib/multimap/benchmarks/bm_nested_multimap_construction.rb +60 -0
  12. data/lib/multimap/benchmarks/bm_nested_multimap_lookup.rb +33 -0
  13. data/lib/multimap/ext/extconf.rb +6 -0
  14. data/lib/multimap/ext/nested_multimap_ext.c +24 -0
  15. data/lib/multimap/extras/graphing.rb +83 -0
  16. data/lib/multimap/lib/multimap.rb +569 -0
  17. data/lib/multimap/lib/multiset.rb +185 -0
  18. data/lib/multimap/lib/nested_multimap.rb +158 -0
  19. data/lib/multimap/spec/enumerable_examples.rb +50 -0
  20. data/lib/multimap/spec/hash_examples.rb +264 -0
  21. data/lib/multimap/spec/multimap_spec.rb +45 -0
  22. data/lib/multimap/spec/multiset_spec.rb +184 -0
  23. data/lib/multimap/spec/nested_multimap_spec.rb +202 -0
  24. data/lib/multimap/spec/set_examples.rb +301 -0
  25. data/lib/multimap/spec/spec_helper.rb +67 -0
  26. data/lib/rubymail/address.rb +17 -0
  27. data/lib/rubymail/base.rb +118 -0
  28. data/lib/rubymail/bounce.rb +31 -0
  29. data/lib/rubymail/client.rb +87 -0
  30. data/lib/rubymail/complaint.rb +31 -0
  31. data/lib/rubymail/domain.rb +34 -0
  32. data/lib/rubymail/list.rb +37 -0
  33. data/lib/rubymail/log.rb +19 -0
  34. data/lib/rubymail/mailbox.rb +41 -0
  35. data/lib/rubymail/message.rb +16 -0
  36. data/lib/rubymail/route.rb +99 -0
  37. data/lib/rubymail/rubymail_error.rb +53 -0
  38. data/lib/rubymail/secure.rb +19 -0
  39. data/lib/rubymail/unsubscribe.rb +31 -0
  40. data/lib/rubymail/webhook.rb +43 -0
  41. data/lib/rubymail.rb +31 -0
  42. data/rubymail.gemspec +18 -0
  43. data/spec/address_spec.rb +27 -0
  44. data/spec/base_spec.rb +132 -0
  45. data/spec/bounce_spec.rb +66 -0
  46. data/spec/client_spec.rb +118 -0
  47. data/spec/complaint_spec.rb +103 -0
  48. data/spec/domain_spec.rb +80 -0
  49. data/spec/helpers/rubymail_helper.rb +9 -0
  50. data/spec/list/member_spec.rb +82 -0
  51. data/spec/list/message_spec.rb +40 -0
  52. data/spec/list_spec.rb +70 -0
  53. data/spec/log_spec.rb +27 -0
  54. data/spec/mailbox_spec.rb +63 -0
  55. data/spec/route_spec.rb +100 -0
  56. data/spec/secure_spec.rb +54 -0
  57. data/spec/spec_helper.rb +10 -0
  58. data/spec/unsubscribe_spec.rb +82 -0
  59. data/spec/webhook_spec.rb +115 -0
  60. metadata +159 -0
@@ -0,0 +1,67 @@
1
+ require 'multiset'
2
+ require 'multimap'
3
+ require 'nested_multimap'
4
+
5
+ require 'enumerable_examples'
6
+ require 'hash_examples'
7
+ require 'set_examples'
8
+
9
+ # Rubinius Hash isn't ordered by insert order
10
+ Spec::Matchers.define :sorted_eql do |expected|
11
+ if defined? Rubinius
12
+ sorter = lambda { |a, b| a.hash <=> b.hash }
13
+ match do |actual|
14
+ expect(actual.sort(&sorter)).to eql(expected.sort(&sorter))
15
+ end
16
+ else
17
+ match do |actual|
18
+ expect(actual).to eql(expected)
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'set'
24
+
25
+ if defined? Rubinius
26
+ class Set
27
+ def <=>(other)
28
+ to_a <=> other.to_a
29
+ end
30
+ end
31
+ end
32
+
33
+ require 'forwardable'
34
+
35
+ class MiniArray
36
+ extend Forwardable
37
+
38
+ attr_accessor :data
39
+
40
+ def initialize(data = [])
41
+ @data = data
42
+ end
43
+
44
+ def initialize_copy(orig)
45
+ @data = orig.data.dup
46
+ end
47
+
48
+ def_delegators :@data, :<<, :each, :delete, :delete_if
49
+
50
+ def ==(other)
51
+ other.is_a?(self.class) && @data == other.data
52
+ end
53
+
54
+ def eql?(other)
55
+ other.is_a?(self.class) && @data.eql?(other.data)
56
+ end
57
+
58
+ if defined? Rubinius
59
+ def hash
60
+ @data.hash
61
+ end
62
+
63
+ def <=>(other)
64
+ @data <=> other.data
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ module Rubymail
2
+ class Address
3
+ def initialize(rubymail)
4
+ @rubymail = rubymail
5
+ end
6
+
7
+ def validate(email)
8
+ Rubymail.submit :get, address_url('validate'), {:address => email}
9
+ end
10
+
11
+ private
12
+
13
+ def address_url(action)
14
+ "#{@rubymail.public_base_url}/address/#{action}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,118 @@
1
+ module Rubymail
2
+ class Base
3
+
4
+ def initialize(options)
5
+ Rubymail.rubymail_host = options.fetch(:rubymail_host) { "api.rubymail.net" }
6
+ Rubymail.protocol = options.fetch(:protocol) { "https" }
7
+ Rubymail.api_version = options.fetch(:api_version) { "v3" }
8
+ Rubymail.test_mode = options.fetch(:test_mode) { false }
9
+ Rubymail.api_key = options.fetch(:api_key) { raise ArgumentError.new(":api_key is a required argument to initialize Rubymail") if Rubymail.api_key.nil? }
10
+ Rubymail.domain = options.fetch(:domain) { nil }
11
+ Rubymail.webhook_url = options.fetch(:webhook_url) { nil }
12
+ Rubymail.public_api_key = options.fetch(:public_api_key) { nil }
13
+ end
14
+
15
+ def base_url
16
+ "#{Rubymail.protocol}://api:#{Rubymail.api_key}@#{Rubymail.rubymail_host}/#{Rubymail.api_version}"
17
+ end
18
+
19
+ def public_base_url
20
+ "#{Rubymail.protocol}://api:#{Rubymail.public_api_key}@#{Rubymail.rubymail_host}/#{Rubymail.api_version}"
21
+ end
22
+
23
+ def mailboxes(domain = Rubymail.domain)
24
+ Rubymail::Mailbox.new(self, domain)
25
+ end
26
+
27
+ def messages(domain = Rubymail.domain)
28
+ @messages ||= Rubymail::Message.new(self, domain)
29
+ end
30
+
31
+ def routes
32
+ @routes ||= Rubymail::Route.new(self)
33
+ end
34
+
35
+ def bounces(domain = Rubymail.domain)
36
+ Rubymail::Bounce.new(self, domain)
37
+ end
38
+
39
+ def domains
40
+ Rubymail::Domain.new(self)
41
+ end
42
+
43
+ def unsubscribes(domain = Rubymail.domain)
44
+ Rubymail::Unsubscribe.new(self, domain)
45
+ end
46
+
47
+ def webhooks(domain = Rubymail.domain, webhook_url = Rubymail.webhook_url)
48
+ Rubymail::Webhook.new(self, domain, webhook_url)
49
+ end
50
+
51
+ def addresses(domain = Rubymail.domain)
52
+ if Rubymail.public_api_key.nil?
53
+ raise ArgumentError.new(":public_api_key is a required argument to validate addresses")
54
+ end
55
+ Rubymail::Address.new(self)
56
+ end
57
+
58
+ def complaints(domain = Rubymail.domain)
59
+ Rubymail::Complaint.new(self, domain)
60
+ end
61
+
62
+ def log(domain=Rubymail.domain)
63
+ Rubymail::Log.new(self, domain)
64
+ end
65
+
66
+ def lists
67
+ @lists ||= Rubymail::MailingList.new(self)
68
+ end
69
+
70
+ def list_members(address)
71
+ Rubymail::MailingList::Member.new(self, address)
72
+ end
73
+
74
+ def secure
75
+ Rubymail::Secure.new(self)
76
+ end
77
+ end
78
+
79
+
80
+ def self.submit(method, url, parameters={})
81
+ begin
82
+ JSON.parse(Client.new(url).send(method, parameters))
83
+ rescue => e
84
+ error_code = e.http_code
85
+ error_message = begin
86
+ JSON(e.http_body)["message"]
87
+ rescue JSON::ParserError
88
+ ''
89
+ end
90
+ error = Rubymail::Error.new(
91
+ :code => error_code || nil,
92
+ :message => error_message || nil
93
+ )
94
+ if error.handle.kind_of? Rubymail::ErrorBase
95
+ raise error.handle
96
+ else
97
+ raise error
98
+ end
99
+ end
100
+ end
101
+
102
+ class << self
103
+ attr_accessor :api_key,
104
+ :api_version,
105
+ :protocol,
106
+ :rubymail_host,
107
+ :test_mode,
108
+ :domain,
109
+ :webhook_url,
110
+ :public_api_key
111
+
112
+ def configure
113
+ yield self
114
+ true
115
+ end
116
+ alias :config :configure
117
+ end
118
+ end
@@ -0,0 +1,31 @@
1
+ module Rubymail
2
+ class Bounce
3
+ def initialize(rubymail, domain)
4
+ @rubymail = rubymail
5
+ @domain = domain
6
+ end
7
+
8
+ def list(options={})
9
+ Rubymail.submit(:get, bounce_url, options)["items"] || []
10
+ end
11
+
12
+ def find(email)
13
+ Rubymail.submit :get, bounce_url(email)
14
+ end
15
+
16
+ def add(email, options={})
17
+ Rubymail.submit :post, bounce_url, {:address => email}.merge(options)
18
+ end
19
+
20
+ def destroy(email)
21
+ Rubymail.submit :delete, bounce_url(email)
22
+ end
23
+
24
+ private
25
+
26
+ def bounce_url(address=nil)
27
+ "#{@rubymail.base_url}/#{@domain}/bounces#{'/' + address if address}"
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,87 @@
1
+ module Rubymail
2
+ class Client
3
+ attr_reader :url
4
+
5
+ def initialize(url)
6
+ @url = url
7
+ end
8
+
9
+ def get(params = {})
10
+ request_path = path
11
+ request_path += "?#{URI.encode_www_form(params)}" if params.any?
12
+
13
+ request = Net::HTTP::Get.new(request_path)
14
+
15
+ make_request(request)
16
+ end
17
+
18
+ def post(params = {})
19
+ request = Net::HTTP::Post.new(path)
20
+ request.set_form_data(params)
21
+
22
+ make_request(request)
23
+ end
24
+
25
+ def put(params = {})
26
+ request = Net::HTTP::Put.new(path)
27
+ request.set_form_data(params)
28
+
29
+ make_request(request)
30
+ end
31
+
32
+ def delete(params = {})
33
+ request = Net::HTTP::Delete.new(path)
34
+ request.set_form_data(params)
35
+
36
+ make_request(request)
37
+ end
38
+
39
+ private
40
+
41
+ def make_request(request)
42
+ set_auth(request)
43
+ response = http_client.request(request)
44
+
45
+ check_for_errors(response)
46
+
47
+ response.body
48
+ end
49
+
50
+ def check_for_errors(response)
51
+ return if response.code == '200'
52
+
53
+ error = ClientError.new
54
+ error.http_code = response.code.to_i
55
+ error.http_body = response.body
56
+ raise error
57
+ end
58
+
59
+ def path
60
+ parsed_url.path
61
+ end
62
+
63
+ def parsed_url
64
+ @parsed_url ||= URI.parse url
65
+ end
66
+
67
+ def http_client
68
+ http = Net::HTTP.new(rubymail_url.host, rubymail_url.port)
69
+ http.use_ssl = true
70
+ http
71
+ end
72
+
73
+ def rubymail_url
74
+ URI.parse Rubymail().base_url
75
+ end
76
+
77
+ def set_auth(request)
78
+ request.basic_auth(parsed_url.user, parsed_url.password)
79
+ end
80
+ end
81
+ end
82
+
83
+ module Rubymail
84
+ class ClientError < StandardError
85
+ attr_accessor :http_code, :http_body
86
+ end
87
+ end
@@ -0,0 +1,31 @@
1
+ module Rubymail
2
+ class Complaint
3
+ def initialize(rubymail, domain)
4
+ @rubymail = rubymail
5
+ @domain = domain
6
+ end
7
+
8
+ def list(options={})
9
+ Rubymail.submit(:get, complaint_url, options)["items"] || []
10
+ end
11
+
12
+ def find(email)
13
+ Rubymail.submit :get, complaint_url(email)
14
+ end
15
+
16
+ def add(email)
17
+ Rubymail.submit :post, complaint_url, {:address => email}
18
+ end
19
+
20
+ def destroy(email)
21
+ Rubymail.submit :delete, complaint_url(email)
22
+ end
23
+
24
+ private
25
+
26
+ def complaint_url(address=nil)
27
+ "#{@rubymail.base_url}/#{@domain}/complaints#{'/' + address if address}"
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ module Rubymail
2
+ class Domain
3
+ def initialize(rubymail)
4
+ @rubymail = rubymail
5
+ end
6
+
7
+ def list(options={})
8
+ Rubymail.submit(:get, domain_url, options)["items"] || []
9
+ end
10
+
11
+ def find(domain)
12
+ Rubymail.submit :get, domain_url(domain)
13
+ end
14
+
15
+ def create(domain, opts = {})
16
+ opts = {name: domain}.merge(opts)
17
+ Rubymail.submit :post, domain_url, opts
18
+ end
19
+
20
+ def delete(domain)
21
+ Rubymail.submit :delete, domain_url(domain)
22
+ end
23
+
24
+ def verify(domain)
25
+ Rubymail.submit :put, "#{domain_url(domain)}/verify"
26
+ end
27
+
28
+ private
29
+
30
+ def domain_url(domain = nil)
31
+ "#{@rubymail.base_url}/domains#{'/' + domain if domain}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ module Rubymail
2
+ class MailingList
3
+ def initialize(rubymail)
4
+ @rubymail = rubymail
5
+ end
6
+
7
+ def list(options={})
8
+ response = Rubymail.submit(:get, list_url, options)["items"] || []
9
+ end
10
+
11
+ def find(address)
12
+ Rubymail.submit :get, list_url(address)
13
+ end
14
+
15
+ def create(address, options={})
16
+ params = {:address => address}
17
+ Rubymail.submit :post, list_url, params.merge(options)
18
+ end
19
+
20
+ def update(address, new_address, options={})
21
+ params = {:address => new_address}
22
+ Rubymail.submit :put, list_url(address), params.merge(options)
23
+ end
24
+
25
+ def delete(address)
26
+ Rubymail.submit :delete, list_url(address)
27
+ end
28
+
29
+
30
+ private
31
+
32
+ def list_url(address=nil)
33
+ "#{@rubymail.base_url}/lists#{'/' + address if address}"
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ module Rubymail
2
+ class Log
3
+ def initialize(rubymail, domain)
4
+ @rubymail = rubymail
5
+ @domain = domain
6
+ end
7
+
8
+ def list(options={})
9
+ Rubymail.submit(:get, log_url, options)
10
+ end
11
+
12
+ private
13
+
14
+
15
+ def log_url
16
+ "#{@rubymail.base_url}/#{@domain}/log"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ module Rubymail
2
+ class Mailbox
3
+
4
+ def initialize(rubymail, domain)
5
+ @rubymail = rubymail
6
+ @domain = domain
7
+ end
8
+
9
+ def list(options={})
10
+ Rubymail.submit(:get, mailbox_url, options)["items"]
11
+ end
12
+
13
+ def create(mailbox_name, password)
14
+ address = "#{mailbox_name}@#{@domain}"
15
+ Rubymail.submit(
16
+ :post,
17
+ mailbox_url,
18
+ {
19
+ :mailbox => address,
20
+ :password => password
21
+ }
22
+ )
23
+ end
24
+
25
+ def update_password(mailbox_name, password)
26
+ Rubymail.submit :put, mailbox_url(mailbox_name), :password => password
27
+ end
28
+
29
+ def destroy(mailbox_name)
30
+ Rubymail.submit :delete, mailbox_url(mailbox_name)
31
+ end
32
+
33
+
34
+ private
35
+
36
+ def mailbox_url(mailbox_name=nil)
37
+ "#{@rubymail.base_url}/#{@domain}/mailboxes#{'/' + mailbox_name if mailbox_name}"
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,16 @@
1
+ module Rubymail
2
+ class Message
3
+ def initialize(rubymail, domain)
4
+ @rubymail = rubymail
5
+ @domain = domain
6
+ end
7
+
8
+ def send_email(parameters={})
9
+ Rubymail.submit(:post, messages_url, parameters)
10
+ end
11
+
12
+ def messages_url
13
+ "#{@rubymail.base_url}/#{@domain}/messages"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,99 @@
1
+ module Rubymail
2
+ class Route
3
+ def initialize(rubymail)
4
+ @rubymail = rubymail
5
+ end
6
+
7
+ def list(options={})
8
+ Rubymail.submit(:get, route_url, options)["items"] || []
9
+ end
10
+
11
+ def find(route_id)
12
+ Rubymail.submit(:get, route_url(route_id))["route"]
13
+ end
14
+
15
+ def create(description, priority, filter, actions)
16
+ data = ::Multimap.new
17
+
18
+ data['priority'] = priority
19
+ data['description'] = description
20
+ data['expression'] = build_filter(filter)
21
+
22
+ actions = build_actions(actions)
23
+
24
+ actions.each do |action|
25
+ data['action'] = action
26
+ end
27
+
28
+ data = data.to_hash
29
+
30
+ # TODO: Raise an error or return false if unable to create route
31
+ Rubymail.submit(:post, route_url, data)["route"]["id"]
32
+ end
33
+
34
+ def update(route_id, params)
35
+ data = ::Multimap.new
36
+
37
+ params = Hash[params.map{ |k, v| [k.to_s, v] }]
38
+
39
+ ['priority', 'description'].each do |key|
40
+ data[key] = params[key] if params.has_key?(key)
41
+ end
42
+
43
+ data['expression'] = build_filter(params['expression']) if params.has_key?('expression')
44
+
45
+ if params.has_key?('actions')
46
+ actions = build_actions(params['actions'])
47
+
48
+ actions.each do |action|
49
+ data['action'] = action
50
+ end
51
+ end
52
+
53
+ data = data.to_hash
54
+
55
+ Rubymail.submit(:put, route_url(route_id), data)
56
+ end
57
+
58
+ def destroy(route_id)
59
+ Rubymail.submit(:delete, route_url(route_id))["id"]
60
+ end
61
+
62
+ private
63
+
64
+ def route_url(route_id=nil)
65
+ "#{@rubymail.base_url}/routes#{'/' + route_id if route_id}"
66
+ end
67
+
68
+ def build_actions(actions)
69
+ _actions = []
70
+
71
+ actions.each do |action|
72
+ case action.first.to_sym
73
+ when :forward
74
+ _actions << "forward(\"#{action.last}\")"
75
+ when :stop
76
+ _actions << "stop()"
77
+ else
78
+ raise Rubymail::Error.new("Unsupported action requested, see http://documentation.rubymail.net/user_manual.html#routes for a list of allowed actions")
79
+ end
80
+ end
81
+
82
+ _actions
83
+ end
84
+
85
+
86
+ def build_filter(filter)
87
+ case filter.first.to_sym
88
+ when :match_recipient
89
+ return "match_recipient('#{filter.last}')"
90
+ when :match_header
91
+ return "match_header('#{filter[1]}', '#{filter.last}')"
92
+ when :catch_all
93
+ return "catch_all()"
94
+ else
95
+ raise Rubymail::Error.new("Unsupported filter requested, see http://documentation.rubymail.net/user_manual.html#routes for a list of allowed filters")
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,53 @@
1
+ module Rubymail
2
+ class Error
3
+ attr_accessor :error
4
+
5
+ def initialize(options={})
6
+ @error =
7
+ case options[:code]
8
+ when 200
9
+ # 200 status code [success code]
10
+ when 404
11
+ Rubymail::NotFound.new(options[:message])
12
+ when 400
13
+ Rubymail::BadRequest.new(options[:message])
14
+ when 401
15
+ Rubymail::Unauthorized.new(options[:message])
16
+ when 402
17
+ Rubymail::ResquestFailed.new(options[:message])
18
+ when 500, 502, 503, 504
19
+ Rubymail::ServerError.new(options[:message])
20
+ else
21
+ Rubymail::ErrorBase.new(options[:message])
22
+ end
23
+ end
24
+
25
+ def handle
26
+ return error.handle
27
+ end
28
+ end
29
+
30
+ class ErrorBase < StandardError
31
+ def handle
32
+ return self
33
+ end
34
+ end
35
+
36
+ class NotFound < ErrorBase
37
+ def handle
38
+ return nil
39
+ end
40
+ end
41
+
42
+ class BadRequest < ErrorBase
43
+ end
44
+
45
+ class Unauthorized < ErrorBase
46
+ end
47
+
48
+ class ResquestFailed < ErrorBase
49
+ end
50
+
51
+ class ServerError < ErrorBase
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module Rubymail
2
+ class Secure
3
+ def initialize(rubymail)
4
+ @rubymail = rubymail
5
+ end
6
+
7
+ def check_request_auth(timestamp, token, signature, offset=-5)
8
+ if offset != 0
9
+ offset = Time.now.to_i + offset * 60
10
+ return false if timestamp < offset
11
+ end
12
+
13
+ return signature == OpenSSL::HMAC.hexdigest(
14
+ OpenSSL::Digest::Digest.new('sha256'),
15
+ Rubymail.api_key,
16
+ '%s%s' % [timestamp, token])
17
+ end
18
+ end
19
+ end